blob: f9e882e1d04d70ba5fbfa5bce67f36ec127d8335 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001068 elms->set(GETTER_INDEX, accessors->SafeGet(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001071 elms->set(SETTER_INDEX, accessors->SafeGet(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001118 elms->set(GETTER_INDEX, accessors->SafeGet(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001121 elms->set(SETTER_INDEX, accessors->SafeGet(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
1292 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (value->IsUndefined() || is_const_property) {
1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 continue;
1304 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 value = function;
1322 }
1323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 global->LocalLookup(*name, &lookup);
1326
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001327 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either.
1331 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001333 attr |= DONT_DELETE;
1334 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // Safari does not allow the invocation of callback setters for
1341 // function declarations. To mimic this behavior, we do not allow
1342 // the invocation of setters for function values. This makes a
1343 // difference for global functions with the same names as event
1344 // handlers such as "function onload() {}". Firefox does call the
1345 // onload setter in those case and Safari does not. We follow
1346 // Safari for compatibility.
1347 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 // Do not change DONT_DELETE to false from true.
1349 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001350 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001351 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1353
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 RETURN_IF_EMPTY_HANDLE(
1355 isolate,
1356 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1357 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001359 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1360 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1361 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001362 RETURN_IF_EMPTY_HANDLE(
1363 isolate,
1364 JSReceiver::SetProperty(global, name, value,
1365 static_cast<PropertyAttributes>(attr),
1366 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 }
1368 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 ASSERT(!isolate->has_pending_exception());
1371 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372}
1373
1374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001375RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 // Declarations are always made in a function or global context. In the
1380 // case of eval code, the context passed is the context of the caller,
1381 // which may be some nested context and not the declaration context.
1382 RUNTIME_ASSERT(args[0]->IsContext());
1383 Handle<Context> context(Context::cast(args[0])->declaration_context());
1384
ager@chromium.org7c537e22008-10-16 08:43:32 +00001385 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001386 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001387 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 int index;
1391 PropertyAttributes attributes;
1392 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001393 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001394 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001395 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396
1397 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1400 // Functions are not read-only.
1401 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1402 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001403 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 }
1405
1406 // Initialize it if necessary.
1407 if (*initial_value != NULL) {
1408 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 ASSERT(holder.is_identical_to(context));
1410 if (((attributes & READ_ONLY) == 0) ||
1411 context->get(index)->IsTheHole()) {
1412 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001415 // Slow case: The property is in the context extension object of a
1416 // function context or the global object of a global context.
1417 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001418 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001420 JSReceiver::SetProperty(object, name, initial_value, mode,
1421 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001427 // "declared" in the function context's extension context or as a
1428 // property of the the global object.
1429 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001430 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001432 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001433 // Context extension objects are allocated lazily.
1434 ASSERT(context->IsFunctionContext());
1435 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001437 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 // Declare the property by setting it to the initial value if provided,
1442 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1443 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001446 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001447 // Declaring a const context slot is a conflicting declaration if
1448 // there is a callback with that name in a prototype. It is
1449 // allowed to introduce const variables in
1450 // JSContextExtensionObjects. They are treated specially in
1451 // SetProperty and no setters are invoked for those since they are
1452 // not real JSObjects.
1453 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001455 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001457 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001459 }
1460 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001461 RETURN_IF_EMPTY_HANDLE(
1462 isolate,
1463 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001464 }
1465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467}
1468
1469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001470RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001472 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001473 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001474 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
1476 // Determine if we need to assign to the variable if it already
1477 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1479 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001481 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001484 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1485 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1486 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487
1488 // According to ECMA-262, section 12.2, page 62, the property must
1489 // not be deletable.
1490 PropertyAttributes attributes = DONT_DELETE;
1491
1492 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001493 // there, there is a property with this name in the prototype chain.
1494 // We follow Safari and Firefox behavior and only set the property
1495 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001496 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001497 // Note that objects can have hidden prototypes, so we need to traverse
1498 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001500 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 while (object->IsJSObject() &&
1502 JSObject::cast(object)->map()->is_hidden_prototype()) {
1503 JSObject* raw_holder = JSObject::cast(object);
1504 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001505 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 HandleScope handle_scope(isolate);
1507 Handle<JSObject> holder(raw_holder);
1508 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1509 // Update the raw pointer in case it's changed due to GC.
1510 raw_holder = *holder;
1511 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1512 // Found an interceptor that's not read only.
1513 if (assign) {
1514 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001515 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 } else {
1517 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001518 }
1519 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001520 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 }
1523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001525 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001526 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001527 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001529 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530}
1531
1532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001533RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // All constants are declared with an initial value. The name
1535 // of the constant is the first argument and the initial value
1536 // is the second.
1537 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001538 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 Handle<Object> value = args.at<Object>(1);
1540
1541 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543
1544 // According to ECMA-262, section 12.2, page 62, the property must
1545 // not be deletable. Since it's a const, it must be READ_ONLY too.
1546 PropertyAttributes attributes =
1547 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1548
1549 // Lookup the property locally in the global object. If it isn't
1550 // there, we add the property and take special precautions to always
1551 // add it as a local property even in case of callbacks in the
1552 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001553 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001554 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 global->LocalLookup(*name, &lookup);
1556 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001557 return global->SetLocalPropertyIgnoreAttributes(*name,
1558 *value,
1559 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001565 HandleScope handle_scope(isolate);
1566 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001568 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 // property through an interceptor and only do it if it's
1570 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001571 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001572 RETURN_IF_EMPTY_HANDLE(
1573 isolate,
1574 JSReceiver::SetProperty(global, name, value, attributes,
1575 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 return *value;
1577 }
1578
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001579 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // constant. For now, we determine this by checking if the
1581 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 PropertyType type = lookup.type();
1584 if (type == FIELD) {
1585 FixedArray* properties = global->properties();
1586 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 properties->set(index, *value);
1589 }
1590 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1592 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001593 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
1595 } else {
1596 // Ignore re-initialization of constants that have already been
1597 // assigned a function value.
1598 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1599 }
1600
1601 // Use the set value as the result of the operation.
1602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 ASSERT(args.length() == 3);
1609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001613 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 RUNTIME_ASSERT(args[1]->IsContext());
1615 Handle<Context> context(Context::cast(args[1])->declaration_context());
1616
1617 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
1619 int index;
1620 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001622 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001623 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001624 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001627 ASSERT(holder->IsContext());
1628 // Property was found in a context. Perform the assignment if we
1629 // found some non-constant or an uninitialized constant.
1630 Handle<Context> context = Handle<Context>::cast(holder);
1631 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1632 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 }
1634 return *value;
1635 }
1636
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001637 // The property could not be found, we introduce it as a property of the
1638 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001639 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 Handle<JSObject> global = Handle<JSObject>(
1641 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001642 // Strict mode not needed (const disallowed in strict mode).
1643 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001645 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 return *value;
1647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 // The property was present in some function's context extension object,
1650 // as a property on the subject of a with, or as a property of the global
1651 // object.
1652 //
1653 // In most situations, eval-introduced consts should still be present in
1654 // the context extension object. However, because declaration and
1655 // initialization are separate, the property might have been deleted
1656 // before we reach the initialization point.
1657 //
1658 // Example:
1659 //
1660 // function f() { eval("delete x; const x;"); }
1661 //
1662 // In that case, the initialization behaves like a normal assignment.
1663 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001665 if (*object == context->extension()) {
1666 // This is the property that was introduced by the const declaration.
1667 // Set it if it hasn't been set before. NOTE: We cannot use
1668 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001669 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001671 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1673
1674 PropertyType type = lookup.type();
1675 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001676 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001677 int index = lookup.GetFieldIndex();
1678 if (properties->get(index)->IsTheHole()) {
1679 properties->set(index, *value);
1680 }
1681 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001682 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1683 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001684 }
1685 } else {
1686 // We should not reach here. Any real, named property should be
1687 // either a field or a dictionary slot.
1688 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 }
1690 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 // The property was found on some other object. Set it if it is not a
1692 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001694 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001695 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001696 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001697 JSReceiver::SetProperty(object, name, value, attributes,
1698 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 return *value;
1703}
1704
1705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001706RUNTIME_FUNCTION(MaybeObject*,
1707 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001710 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001711 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001712 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001713 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001714 }
1715 return *object;
1716}
1717
1718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001722 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1723 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001727 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001728 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 RUNTIME_ASSERT(index >= 0);
1730 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001732 Handle<Object> result = RegExpImpl::Exec(regexp,
1733 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001735 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 if (result.is_null()) return Failure::Exception();
1737 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001743 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001744 if (elements_count < 0 ||
1745 elements_count > FixedArray::kMaxLength ||
1746 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 Object* new_object;
1750 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1756 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 {
1760 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 }
1765 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 array->set_elements(elements);
1768 array->set_length(Smi::FromInt(elements_count));
1769 // Write in-object properties after the length of the array.
1770 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1771 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1772 return array;
1773}
1774
1775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 AssertNoAllocation no_alloc;
1778 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001779 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1780 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001781
1782 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001784
1785 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001787
1788 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Map* map = regexp->map();
1792 Object* constructor = map->constructor();
1793 if (constructor->IsJSFunction() &&
1794 JSFunction::cast(constructor)->initial_map() == map) {
1795 // If we still have the original map, set in-object properties directly.
1796 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001797 // Both true and false are immovable immortal objects so no need for write
1798 // barrier.
1799 regexp->InObjectPropertyAtPut(
1800 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1801 regexp->InObjectPropertyAtPut(
1802 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1803 regexp->InObjectPropertyAtPut(
1804 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1806 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001808 return regexp;
1809 }
1810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001812 PropertyAttributes final =
1813 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1814 PropertyAttributes writable =
1815 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 source,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 global,
1824 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 ignoreCase,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 multiline,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 Smi::FromInt(0),
1838 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
1840 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001841 return regexp;
1842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001848 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001849 // This is necessary to enable fast checks for absence of elements
1850 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001852 return Smi::FromInt(0);
1853}
1854
1855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1857 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001858 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001859 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1861 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1862 Handle<JSFunction> optimized =
1863 isolate->factory()->NewFunction(key,
1864 JS_OBJECT_TYPE,
1865 JSObject::kHeaderSize,
1866 code,
1867 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001869 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 return optimized;
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001876 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001877 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001879 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1880 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1881 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1882 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1883 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1884 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1885 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001886
1887 return *holder;
1888}
1889
1890
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001892 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001893 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001894
1895 if (!callable->IsJSFunction()) {
1896 HandleScope scope(isolate);
1897 bool threw = false;
1898 Handle<Object> delegate =
1899 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1900 if (threw) return Failure::Exception();
1901 callable = JSFunction::cast(*delegate);
1902 }
1903 JSFunction* function = JSFunction::cast(callable);
1904
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001905 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001906 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001907 return isolate->heap()->undefined_value();
1908 }
1909 // Returns undefined for strict or native functions, or
1910 // the associated global receiver for "normal" functions.
1911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001912 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001913 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001914 return global_context->global()->global_receiver();
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001919 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001921 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001922 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 Handle<String> pattern = args.at<String>(2);
1924 Handle<String> flags = args.at<String>(3);
1925
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001926 // Get the RegExp function from the context in the literals array.
1927 // This is the RegExp function from the context in which the
1928 // function was created. We do not use the RegExp function from the
1929 // current global context because this might be the RegExp function
1930 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001931 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001932 Handle<JSFunction>(
1933 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 // Compute the regular expression literal.
1935 bool has_pending_exception;
1936 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1938 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 return Failure::Exception();
1942 }
1943 literals->set(index, *regexp);
1944 return *regexp;
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001952 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 return f->shared()->name();
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 2);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1962 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001963 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001965}
1966
1967
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001971 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001972 return isolate->heap()->ToBoolean(
1973 f->shared()->name_should_print_as_anonymous());
1974}
1975
1976
1977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001981 f->shared()->set_name_should_print_as_anonymous(true);
1982 return isolate->heap()->undefined_value();
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001990 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 Object* obj = f->RemovePrototype();
1992 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 ASSERT(args.length() == 1);
2001
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002002 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2004 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005
2006 return *GetScriptWrapper(Handle<Script>::cast(script));
2007}
2008
2009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002010RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002011 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 ASSERT(args.length() == 1);
2013
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002014 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002015 Handle<SharedFunctionInfo> shared(f->shared());
2016 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 NoHandleAllocation ha;
2022 ASSERT(args.length() == 1);
2023
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002024 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 int pos = fun->shared()->start_position();
2026 return Smi::FromInt(pos);
2027}
2028
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002031 ASSERT(args.length() == 2);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002034 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2035
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002036 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2037
2038 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002039 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002047 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2048 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 NoHandleAllocation ha;
2056 ASSERT(args.length() == 2);
2057
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002058 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2059 CONVERT_SMI_ARG_CHECKED(length, 1);
2060 fun->shared()->set_length(length);
2061 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062}
2063
2064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002065RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002066 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067 ASSERT(args.length() == 2);
2068
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002069 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002070 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002071 Object* obj;
2072 { MaybeObject* maybe_obj =
2073 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2074 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 return args[0]; // return TOS
2077}
2078
2079
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2081 NoHandleAllocation ha;
2082 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002083 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002084
2085 MaybeObject* maybe_name =
2086 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2087 String* name;
2088 if (!maybe_name->To(&name)) return maybe_name;
2089
2090 if (function->HasFastProperties()) {
2091 // Construct a new field descriptor with updated attributes.
2092 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2093 int index = instance_desc->Search(name);
2094 ASSERT(index != DescriptorArray::kNotFound);
2095 PropertyDetails details(instance_desc->GetDetails(index));
2096 CallbacksDescriptor new_desc(name,
2097 instance_desc->GetValue(index),
2098 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2099 details.index());
2100 // Construct a new field descriptors array containing the new descriptor.
2101 Object* descriptors_unchecked;
2102 { MaybeObject* maybe_descriptors_unchecked =
2103 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2104 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2105 return maybe_descriptors_unchecked;
2106 }
2107 }
2108 DescriptorArray* new_descriptors =
2109 DescriptorArray::cast(descriptors_unchecked);
2110 // Create a new map featuring the new field descriptors array.
2111 Object* map_unchecked;
2112 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2113 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2114 return maybe_map_unchecked;
2115 }
2116 }
2117 Map* new_map = Map::cast(map_unchecked);
2118 new_map->set_instance_descriptors(new_descriptors);
2119 function->set_map(new_map);
2120 } else { // Dictionary properties.
2121 // Directly manipulate the property details.
2122 int entry = function->property_dictionary()->FindEntry(name);
2123 ASSERT(entry != StringDictionary::kNotFound);
2124 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2125 PropertyDetails new_details(
2126 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2127 details.type(),
2128 details.index());
2129 function->property_dictionary()->DetailsAtPut(entry, new_details);
2130 }
2131 return function;
2132}
2133
2134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002135RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002136 NoHandleAllocation ha;
2137 ASSERT(args.length() == 1);
2138
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002139 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002140 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002141}
2142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002149 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002150}
2151
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 ASSERT(args.length() == 2);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 Handle<Object> code = args.at<Object>(1);
2159
2160 Handle<Context> context(target->context());
2161
2162 if (!code->IsNull()) {
2163 RUNTIME_ASSERT(code->IsJSFunction());
2164 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002165 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002166
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002167 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 return Failure::Exception();
2169 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170 // Since we don't store the source for this we should never
2171 // optimize this.
2172 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002173 // Set the code, scope info, formal parameter count,
2174 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002175 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002176 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002177 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002178 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002181 // Set the source code of the target function to undefined.
2182 // SetCode is only used for built-in constructors like String,
2183 // Array, and Object, and some web code
2184 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002186 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002187 // Clear the optimization hints related to the compiled code as these are no
2188 // longer valid when the code is overwritten.
2189 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 context = Handle<Context>(fun->context());
2191
2192 // Make sure we get a fresh copy of the literal vector to avoid
2193 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002194 int number_of_literals = fun->NumberOfLiterals();
2195 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002196 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002198 // Insert the object, regexp and array functions in the literals
2199 // array prefix. These are the functions that will be used when
2200 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002201 literals->set(JSFunction::kLiteralGlobalContextIndex,
2202 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002204 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002206
2207 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2208 isolate->logger()->LogExistingFunction(
2209 shared, Handle<Code>(shared->code()));
2210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 }
2212
2213 target->set_context(*context);
2214 return *target;
2215}
2216
2217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002218RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002219 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002221 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002222 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002223 RUNTIME_ASSERT(num >= 0);
2224 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002226}
2227
2228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2230 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002231 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002232 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 }
2236 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002237 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002238}
2239
2240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002241RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242 NoHandleAllocation ha;
2243 ASSERT(args.length() == 2);
2244
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002245 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002246 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002247 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002248
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 uint32_t i = 0;
2250 if (index->IsSmi()) {
2251 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002252 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253 i = value;
2254 } else {
2255 ASSERT(index->IsHeapNumber());
2256 double value = HeapNumber::cast(index)->value();
2257 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259
2260 // Flatten the string. If someone wants to get a char at an index
2261 // in a cons string, it is likely that more indices will be
2262 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002263 Object* flat;
2264 { MaybeObject* maybe_flat = subject->TryFlatten();
2265 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2266 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002267 subject = String::cast(flat);
2268
2269 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002270 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002271 }
2272
2273 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002274}
2275
2276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002277RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278 NoHandleAllocation ha;
2279 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002280 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281}
2282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283
2284class FixedArrayBuilder {
2285 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002286 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2287 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002288 length_(0),
2289 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 // Require a non-zero initial size. Ensures that doubling the size to
2291 // extend the array will work.
2292 ASSERT(initial_capacity > 0);
2293 }
2294
2295 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2296 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297 length_(0),
2298 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 ASSERT(length_ < capacity());
2328 array_->set(length_, value);
2329 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002330 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002331 }
2332
2333 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 ASSERT(length_ < capacity());
2336 array_->set(length_, value);
2337 length_++;
2338 }
2339
2340 Handle<FixedArray> array() {
2341 return array_;
2342 }
2343
2344 int length() {
2345 return length_;
2346 }
2347
2348 int capacity() {
2349 return array_->length();
2350 }
2351
2352 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002353 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002354 result_array->set_length(Smi::FromInt(length_));
2355 return result_array;
2356 }
2357
2358 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 target_array->set_length(Smi::FromInt(length_));
2361 return target_array;
2362 }
2363
2364 private:
2365 Handle<FixedArray> array_;
2366 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002367 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368};
2369
2370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002372const int kStringBuilderConcatHelperLengthBits = 11;
2373const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374
2375template <typename schar>
2376static inline void StringBuilderConcatHelper(String*,
2377 schar*,
2378 FixedArray*,
2379 int);
2380
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2382 StringBuilderSubstringLength;
2383typedef BitField<int,
2384 kStringBuilderConcatHelperLengthBits,
2385 kStringBuilderConcatHelperPositionBits>
2386 StringBuilderSubstringPosition;
2387
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388
2389class ReplacementStringBuilder {
2390 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002391 ReplacementStringBuilder(Heap* heap,
2392 Handle<String> subject,
2393 int estimated_part_count)
2394 : heap_(heap),
2395 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002398 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 // Require a non-zero initial size. Ensures that doubling the size to
2400 // extend the array will work.
2401 ASSERT(estimated_part_count > 0);
2402 }
2403
lrn@chromium.org25156de2010-04-06 13:10:27 +00002404 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2405 int from,
2406 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 ASSERT(from >= 0);
2408 int length = to - from;
2409 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 if (StringBuilderSubstringLength::is_valid(length) &&
2411 StringBuilderSubstringPosition::is_valid(from)) {
2412 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2413 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002414 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002416 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002417 builder->Add(Smi::FromInt(-length));
2418 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002420 }
2421
2422
2423 void EnsureCapacity(int elements) {
2424 array_builder_.EnsureCapacity(elements);
2425 }
2426
2427
2428 void AddSubjectSlice(int from, int to) {
2429 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002430 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 }
2432
2433
2434 void AddString(Handle<String> string) {
2435 int length = string->length();
2436 ASSERT(length > 0);
2437 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002438 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 is_ascii_ = false;
2440 }
2441 IncrementCharacterCount(length);
2442 }
2443
2444
2445 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002447 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
2449
2450 Handle<String> joined_string;
2451 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002452 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002454 char* char_buffer = seq->GetChars();
2455 StringBuilderConcatHelper(*subject_,
2456 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 *array_builder_.array(),
2458 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 } else {
2461 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 uc16* char_buffer = seq->GetChars();
2465 StringBuilderConcatHelper(*subject_,
2466 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002467 *array_builder_.array(),
2468 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002469 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471 return joined_string;
2472 }
2473
2474
2475 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002476 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 V8::FatalProcessOutOfMemory("String.replace result too large.");
2478 }
2479 character_count_ += by;
2480 }
2481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002483 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002484 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002485
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002487 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2488 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 }
2490
2491
ager@chromium.org04921a82011-06-27 13:21:41 +00002492 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2493 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 }
2495
2496
2497 void AddElement(Object* element) {
2498 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002499 ASSERT(array_builder_.capacity() > array_builder_.length());
2500 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 }
2502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002503 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002504 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 int character_count_;
2507 bool is_ascii_;
2508};
2509
2510
2511class CompiledReplacement {
2512 public:
2513 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002514 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515
2516 void Compile(Handle<String> replacement,
2517 int capture_count,
2518 int subject_length);
2519
2520 void Apply(ReplacementStringBuilder* builder,
2521 int match_from,
2522 int match_to,
2523 Handle<JSArray> last_match_info);
2524
2525 // Number of distinct parts of the replacement pattern.
2526 int parts() {
2527 return parts_.length();
2528 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002529
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002530 bool simple_hint() {
2531 return simple_hint_;
2532 }
2533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 private:
2535 enum PartType {
2536 SUBJECT_PREFIX = 1,
2537 SUBJECT_SUFFIX,
2538 SUBJECT_CAPTURE,
2539 REPLACEMENT_SUBSTRING,
2540 REPLACEMENT_STRING,
2541
2542 NUMBER_OF_PART_TYPES
2543 };
2544
2545 struct ReplacementPart {
2546 static inline ReplacementPart SubjectMatch() {
2547 return ReplacementPart(SUBJECT_CAPTURE, 0);
2548 }
2549 static inline ReplacementPart SubjectCapture(int capture_index) {
2550 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2551 }
2552 static inline ReplacementPart SubjectPrefix() {
2553 return ReplacementPart(SUBJECT_PREFIX, 0);
2554 }
2555 static inline ReplacementPart SubjectSuffix(int subject_length) {
2556 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2557 }
2558 static inline ReplacementPart ReplacementString() {
2559 return ReplacementPart(REPLACEMENT_STRING, 0);
2560 }
2561 static inline ReplacementPart ReplacementSubString(int from, int to) {
2562 ASSERT(from >= 0);
2563 ASSERT(to > from);
2564 return ReplacementPart(-from, to);
2565 }
2566
2567 // If tag <= 0 then it is the negation of a start index of a substring of
2568 // the replacement pattern, otherwise it's a value from PartType.
2569 ReplacementPart(int tag, int data)
2570 : tag(tag), data(data) {
2571 // Must be non-positive or a PartType value.
2572 ASSERT(tag < NUMBER_OF_PART_TYPES);
2573 }
2574 // Either a value of PartType or a non-positive number that is
2575 // the negation of an index into the replacement string.
2576 int tag;
2577 // The data value's interpretation depends on the value of tag:
2578 // tag == SUBJECT_PREFIX ||
2579 // tag == SUBJECT_SUFFIX: data is unused.
2580 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2581 // tag == REPLACEMENT_SUBSTRING ||
2582 // tag == REPLACEMENT_STRING: data is index into array of substrings
2583 // of the replacement string.
2584 // tag <= 0: Temporary representation of the substring of the replacement
2585 // string ranging over -tag .. data.
2586 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2587 // substring objects.
2588 int data;
2589 };
2590
2591 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002592 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 Vector<Char> characters,
2594 int capture_count,
2595 int subject_length) {
2596 int length = characters.length();
2597 int last = 0;
2598 for (int i = 0; i < length; i++) {
2599 Char c = characters[i];
2600 if (c == '$') {
2601 int next_index = i + 1;
2602 if (next_index == length) { // No next character!
2603 break;
2604 }
2605 Char c2 = characters[next_index];
2606 switch (c2) {
2607 case '$':
2608 if (i > last) {
2609 // There is a substring before. Include the first "$".
2610 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2611 last = next_index + 1; // Continue after the second "$".
2612 } else {
2613 // Let the next substring start with the second "$".
2614 last = next_index;
2615 }
2616 i = next_index;
2617 break;
2618 case '`':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectPrefix());
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '\'':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '&':
2635 if (i > last) {
2636 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2637 }
2638 parts->Add(ReplacementPart::SubjectMatch());
2639 i = next_index;
2640 last = i + 1;
2641 break;
2642 case '0':
2643 case '1':
2644 case '2':
2645 case '3':
2646 case '4':
2647 case '5':
2648 case '6':
2649 case '7':
2650 case '8':
2651 case '9': {
2652 int capture_ref = c2 - '0';
2653 if (capture_ref > capture_count) {
2654 i = next_index;
2655 continue;
2656 }
2657 int second_digit_index = next_index + 1;
2658 if (second_digit_index < length) {
2659 // Peek ahead to see if we have two digits.
2660 Char c3 = characters[second_digit_index];
2661 if ('0' <= c3 && c3 <= '9') { // Double digits.
2662 int double_digit_ref = capture_ref * 10 + c3 - '0';
2663 if (double_digit_ref <= capture_count) {
2664 next_index = second_digit_index;
2665 capture_ref = double_digit_ref;
2666 }
2667 }
2668 }
2669 if (capture_ref > 0) {
2670 if (i > last) {
2671 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2672 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002673 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2675 last = next_index + 1;
2676 }
2677 i = next_index;
2678 break;
2679 }
2680 default:
2681 i = next_index;
2682 break;
2683 }
2684 }
2685 }
2686 if (length > last) {
2687 if (last == 0) {
2688 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002689 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002690 } else {
2691 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2692 }
2693 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002694 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002695 }
2696
2697 ZoneList<ReplacementPart> parts_;
2698 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002699 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700};
2701
2702
2703void CompiledReplacement::Compile(Handle<String> replacement,
2704 int capture_count,
2705 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002706 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002707 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002708 String::FlatContent content = replacement->GetFlatContent();
2709 ASSERT(content.IsFlat());
2710 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002711 simple_hint_ = ParseReplacementPattern(&parts_,
2712 content.ToAsciiVector(),
2713 capture_count,
2714 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 } else {
2716 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002717 simple_hint_ = ParseReplacementPattern(&parts_,
2718 content.ToUC16Vector(),
2719 capture_count,
2720 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002721 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002724 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int substring_index = 0;
2726 for (int i = 0, n = parts_.length(); i < n; i++) {
2727 int tag = parts_[i].tag;
2728 if (tag <= 0) { // A replacement string slice.
2729 int from = -tag;
2730 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002731 replacement_substrings_.Add(
2732 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002733 parts_[i].tag = REPLACEMENT_SUBSTRING;
2734 parts_[i].data = substring_index;
2735 substring_index++;
2736 } else if (tag == REPLACEMENT_STRING) {
2737 replacement_substrings_.Add(replacement);
2738 parts_[i].data = substring_index;
2739 substring_index++;
2740 }
2741 }
2742}
2743
2744
2745void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2746 int match_from,
2747 int match_to,
2748 Handle<JSArray> last_match_info) {
2749 for (int i = 0, n = parts_.length(); i < n; i++) {
2750 ReplacementPart part = parts_[i];
2751 switch (part.tag) {
2752 case SUBJECT_PREFIX:
2753 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2754 break;
2755 case SUBJECT_SUFFIX: {
2756 int subject_length = part.data;
2757 if (match_to < subject_length) {
2758 builder->AddSubjectSlice(match_to, subject_length);
2759 }
2760 break;
2761 }
2762 case SUBJECT_CAPTURE: {
2763 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002764 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002765 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2766 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2767 if (from >= 0 && to > from) {
2768 builder->AddSubjectSlice(from, to);
2769 }
2770 break;
2771 }
2772 case REPLACEMENT_SUBSTRING:
2773 case REPLACEMENT_STRING:
2774 builder->AddString(replacement_substrings_[part.data]);
2775 break;
2776 default:
2777 UNREACHABLE();
2778 }
2779 }
2780}
2781
2782
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002783void FindAsciiStringIndices(Vector<const char> subject,
2784 char pattern,
2785 ZoneList<int>* indices,
2786 unsigned int limit) {
2787 ASSERT(limit > 0);
2788 // Collect indices of pattern in subject using memchr.
2789 // Stop after finding at most limit values.
2790 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2791 const char* subject_end = subject_start + subject.length();
2792 const char* pos = subject_start;
2793 while (limit > 0) {
2794 pos = reinterpret_cast<const char*>(
2795 memchr(pos, pattern, subject_end - pos));
2796 if (pos == NULL) return;
2797 indices->Add(static_cast<int>(pos - subject_start));
2798 pos++;
2799 limit--;
2800 }
2801}
2802
2803
2804template <typename SubjectChar, typename PatternChar>
2805void FindStringIndices(Isolate* isolate,
2806 Vector<const SubjectChar> subject,
2807 Vector<const PatternChar> pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 ASSERT(limit > 0);
2811 // Collect indices of pattern in subject.
2812 // Stop after finding at most limit values.
2813 int pattern_length = pattern.length();
2814 int index = 0;
2815 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2816 while (limit > 0) {
2817 index = search.Search(subject, index);
2818 if (index < 0) return;
2819 indices->Add(index);
2820 index += pattern_length;
2821 limit--;
2822 }
2823}
2824
2825
2826void FindStringIndicesDispatch(Isolate* isolate,
2827 String* subject,
2828 String* pattern,
2829 ZoneList<int>* indices,
2830 unsigned int limit) {
2831 {
2832 AssertNoAllocation no_gc;
2833 String::FlatContent subject_content = subject->GetFlatContent();
2834 String::FlatContent pattern_content = pattern->GetFlatContent();
2835 ASSERT(subject_content.IsFlat());
2836 ASSERT(pattern_content.IsFlat());
2837 if (subject_content.IsAscii()) {
2838 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2839 if (pattern_content.IsAscii()) {
2840 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2841 if (pattern_vector.length() == 1) {
2842 FindAsciiStringIndices(subject_vector,
2843 pattern_vector[0],
2844 indices,
2845 limit);
2846 } else {
2847 FindStringIndices(isolate,
2848 subject_vector,
2849 pattern_vector,
2850 indices,
2851 limit);
2852 }
2853 } else {
2854 FindStringIndices(isolate,
2855 subject_vector,
2856 pattern_content.ToUC16Vector(),
2857 indices,
2858 limit);
2859 }
2860 } else {
2861 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002862 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToAsciiVector(),
2866 indices,
2867 limit);
2868 } else {
2869 FindStringIndices(isolate,
2870 subject_vector,
2871 pattern_content.ToUC16Vector(),
2872 indices,
2873 limit);
2874 }
2875 }
2876 }
2877}
2878
2879
2880template<typename ResultSeqString>
2881MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2882 Isolate* isolate,
2883 Handle<String> subject,
2884 Handle<JSRegExp> pattern_regexp,
2885 Handle<String> replacement) {
2886 ASSERT(subject->IsFlat());
2887 ASSERT(replacement->IsFlat());
2888
2889 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2890 ZoneList<int> indices(8);
2891 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2892 String* pattern =
2893 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2894 int subject_len = subject->length();
2895 int pattern_len = pattern->length();
2896 int replacement_len = replacement->length();
2897
2898 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2899
2900 int matches = indices.length();
2901 if (matches == 0) return *subject;
2902
2903 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2904 int subject_pos = 0;
2905 int result_pos = 0;
2906
2907 Handle<ResultSeqString> result;
2908 if (ResultSeqString::kHasAsciiEncoding) {
2909 result = Handle<ResultSeqString>::cast(
2910 isolate->factory()->NewRawAsciiString(result_len));
2911 } else {
2912 result = Handle<ResultSeqString>::cast(
2913 isolate->factory()->NewRawTwoByteString(result_len));
2914 }
2915
2916 for (int i = 0; i < matches; i++) {
2917 // Copy non-matched subject content.
2918 if (subject_pos < indices.at(i)) {
2919 String::WriteToFlat(*subject,
2920 result->GetChars() + result_pos,
2921 subject_pos,
2922 indices.at(i));
2923 result_pos += indices.at(i) - subject_pos;
2924 }
2925
2926 // Replace match.
2927 if (replacement_len > 0) {
2928 String::WriteToFlat(*replacement,
2929 result->GetChars() + result_pos,
2930 0,
2931 replacement_len);
2932 result_pos += replacement_len;
2933 }
2934
2935 subject_pos = indices.at(i) + pattern_len;
2936 }
2937 // Add remaining subject content at the end.
2938 if (subject_pos < subject_len) {
2939 String::WriteToFlat(*subject,
2940 result->GetChars() + result_pos,
2941 subject_pos,
2942 subject_len);
2943 }
2944 return *result;
2945}
2946
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002947
lrn@chromium.org303ada72010-10-27 09:33:13 +00002948MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002950 String* subject,
2951 JSRegExp* regexp,
2952 String* replacement,
2953 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 ASSERT(subject->IsFlat());
2955 ASSERT(replacement->IsFlat());
2956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002958
2959 int length = subject->length();
2960 Handle<String> subject_handle(subject);
2961 Handle<JSRegExp> regexp_handle(regexp);
2962 Handle<String> replacement_handle(replacement);
2963 Handle<JSArray> last_match_info_handle(last_match_info);
2964 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2965 subject_handle,
2966 0,
2967 last_match_info_handle);
2968 if (match.is_null()) {
2969 return Failure::Exception();
2970 }
2971 if (match->IsNull()) {
2972 return *subject_handle;
2973 }
2974
2975 int capture_count = regexp_handle->CaptureCount();
2976
2977 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002978 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 CompiledReplacement compiled_replacement;
2980 compiled_replacement.Compile(replacement_handle,
2981 capture_count,
2982 length);
2983
2984 bool is_global = regexp_handle->GetFlags().is_global();
2985
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002986 // Shortcut for simple non-regexp global replacements
2987 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002988 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002989 compiled_replacement.simple_hint()) {
2990 if (subject_handle->HasOnlyAsciiChars() &&
2991 replacement_handle->HasOnlyAsciiChars()) {
2992 return StringReplaceStringWithString<SeqAsciiString>(
2993 isolate, subject_handle, regexp_handle, replacement_handle);
2994 } else {
2995 return StringReplaceStringWithString<SeqTwoByteString>(
2996 isolate, subject_handle, regexp_handle, replacement_handle);
2997 }
2998 }
2999
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003000 // Guessing the number of parts that the final result string is built
3001 // from. Global regexps can match any number of times, so we guess
3002 // conservatively.
3003 int expected_parts =
3004 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003005 ReplacementStringBuilder builder(isolate->heap(),
3006 subject_handle,
3007 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008
3009 // Index of end of last match.
3010 int prev = 0;
3011
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003012 // Number of parts added by compiled replacement plus preceeding
3013 // string and possibly suffix after last match. It is possible for
3014 // all components to use two elements when encoded as two smis.
3015 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003016 bool matched = true;
3017 do {
3018 ASSERT(last_match_info_handle->HasFastElements());
3019 // Increase the capacity of the builder before entering local handle-scope,
3020 // so its internal buffer can safely allocate a new handle if it grows.
3021 builder.EnsureCapacity(parts_added_per_loop);
3022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003024 int start, end;
3025 {
3026 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003027 FixedArray* match_info_array =
3028 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029
3030 ASSERT_EQ(capture_count * 2 + 2,
3031 RegExpImpl::GetLastCaptureCount(match_info_array));
3032 start = RegExpImpl::GetCapture(match_info_array, 0);
3033 end = RegExpImpl::GetCapture(match_info_array, 1);
3034 }
3035
3036 if (prev < start) {
3037 builder.AddSubjectSlice(prev, start);
3038 }
3039 compiled_replacement.Apply(&builder,
3040 start,
3041 end,
3042 last_match_info_handle);
3043 prev = end;
3044
3045 // Only continue checking for global regexps.
3046 if (!is_global) break;
3047
3048 // Continue from where the match ended, unless it was an empty match.
3049 int next = end;
3050 if (start == end) {
3051 next = end + 1;
3052 if (next > length) break;
3053 }
3054
3055 match = RegExpImpl::Exec(regexp_handle,
3056 subject_handle,
3057 next,
3058 last_match_info_handle);
3059 if (match.is_null()) {
3060 return Failure::Exception();
3061 }
3062 matched = !match->IsNull();
3063 } while (matched);
3064
3065 if (prev < length) {
3066 builder.AddSubjectSlice(prev, length);
3067 }
3068
3069 return *(builder.ToString());
3070}
3071
3072
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003074MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003075 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003076 String* subject,
3077 JSRegExp* regexp,
3078 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003079 ASSERT(subject->IsFlat());
3080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082
3083 Handle<String> subject_handle(subject);
3084 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003085
3086 // Shortcut for simple non-regexp global replacements
3087 if (regexp_handle->GetFlags().is_global() &&
3088 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3089 Handle<String> empty_string_handle(HEAP->empty_string());
3090 if (subject_handle->HasOnlyAsciiChars()) {
3091 return StringReplaceStringWithString<SeqAsciiString>(
3092 isolate, subject_handle, regexp_handle, empty_string_handle);
3093 } else {
3094 return StringReplaceStringWithString<SeqTwoByteString>(
3095 isolate, subject_handle, regexp_handle, empty_string_handle);
3096 }
3097 }
3098
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 Handle<JSArray> last_match_info_handle(last_match_info);
3100 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3101 subject_handle,
3102 0,
3103 last_match_info_handle);
3104 if (match.is_null()) return Failure::Exception();
3105 if (match->IsNull()) return *subject_handle;
3106
3107 ASSERT(last_match_info_handle->HasFastElements());
3108
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003109 int start, end;
3110 {
3111 AssertNoAllocation match_info_array_is_not_in_a_handle;
3112 FixedArray* match_info_array =
3113 FixedArray::cast(last_match_info_handle->elements());
3114
3115 start = RegExpImpl::GetCapture(match_info_array, 0);
3116 end = RegExpImpl::GetCapture(match_info_array, 1);
3117 }
3118
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003119 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 int new_length = length - (end - start);
3121 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003123 }
3124 Handle<ResultSeqString> answer;
3125 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003126 answer = Handle<ResultSeqString>::cast(
3127 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003129 answer = Handle<ResultSeqString>::cast(
3130 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003131 }
3132
3133 // If the regexp isn't global, only match once.
3134 if (!regexp_handle->GetFlags().is_global()) {
3135 if (start > 0) {
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars(),
3138 0,
3139 start);
3140 }
3141 if (end < length) {
3142 String::WriteToFlat(*subject_handle,
3143 answer->GetChars() + start,
3144 end,
3145 length);
3146 }
3147 return *answer;
3148 }
3149
3150 int prev = 0; // Index of end of last match.
3151 int next = 0; // Start of next search (prev unless last match was empty).
3152 int position = 0;
3153
3154 do {
3155 if (prev < start) {
3156 // Add substring subject[prev;start] to answer string.
3157 String::WriteToFlat(*subject_handle,
3158 answer->GetChars() + position,
3159 prev,
3160 start);
3161 position += start - prev;
3162 }
3163 prev = end;
3164 next = end;
3165 // Continue from where the match ended, unless it was an empty match.
3166 if (start == end) {
3167 next++;
3168 if (next > length) break;
3169 }
3170 match = RegExpImpl::Exec(regexp_handle,
3171 subject_handle,
3172 next,
3173 last_match_info_handle);
3174 if (match.is_null()) return Failure::Exception();
3175 if (match->IsNull()) break;
3176
3177 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003178 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003179 {
3180 AssertNoAllocation match_info_array_is_not_in_a_handle;
3181 FixedArray* match_info_array =
3182 FixedArray::cast(last_match_info_handle->elements());
3183 start = RegExpImpl::GetCapture(match_info_array, 0);
3184 end = RegExpImpl::GetCapture(match_info_array, 1);
3185 }
3186 } while (true);
3187
3188 if (prev < length) {
3189 // Add substring subject[prev;length] to answer string.
3190 String::WriteToFlat(*subject_handle,
3191 answer->GetChars() + position,
3192 prev,
3193 length);
3194 position += length - prev;
3195 }
3196
3197 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003198 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003199 }
3200
3201 // Shorten string and fill
3202 int string_size = ResultSeqString::SizeFor(position);
3203 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3204 int delta = allocated_string_size - string_size;
3205
3206 answer->set_length(position);
3207 if (delta == 0) return *answer;
3208
3209 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003211 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003212 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003213 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003214
3215 return *answer;
3216}
3217
3218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003220 ASSERT(args.length() == 4);
3221
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003222 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003223 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003224 Object* flat_subject;
3225 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3226 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3227 return maybe_flat_subject;
3228 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 }
3230 subject = String::cast(flat_subject);
3231 }
3232
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003233 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003234 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235 Object* flat_replacement;
3236 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3237 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3238 return maybe_flat_replacement;
3239 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 }
3241 replacement = String::cast(flat_replacement);
3242 }
3243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003244 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3245 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003246
3247 ASSERT(last_match_info->HasFastElements());
3248
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 if (replacement->length() == 0) {
3250 if (subject->HasOnlyAsciiChars()) {
3251 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003253 } else {
3254 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003255 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003256 }
3257 }
3258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003259 return StringReplaceRegExpWithString(isolate,
3260 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003261 regexp,
3262 replacement,
3263 last_match_info);
3264}
3265
3266
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003267Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3268 Handle<String> subject,
3269 Handle<String> search,
3270 Handle<String> replace,
3271 bool* found,
3272 int recursion_limit) {
3273 if (recursion_limit == 0) return Handle<String>::null();
3274 if (subject->IsConsString()) {
3275 ConsString* cons = ConsString::cast(*subject);
3276 Handle<String> first = Handle<String>(cons->first());
3277 Handle<String> second = Handle<String>(cons->second());
3278 Handle<String> new_first =
3279 StringReplaceOneCharWithString(isolate,
3280 first,
3281 search,
3282 replace,
3283 found,
3284 recursion_limit - 1);
3285 if (*found) return isolate->factory()->NewConsString(new_first, second);
3286 if (new_first.is_null()) return new_first;
3287
3288 Handle<String> new_second =
3289 StringReplaceOneCharWithString(isolate,
3290 second,
3291 search,
3292 replace,
3293 found,
3294 recursion_limit - 1);
3295 if (*found) return isolate->factory()->NewConsString(first, new_second);
3296 if (new_second.is_null()) return new_second;
3297
3298 return subject;
3299 } else {
3300 int index = StringMatch(isolate, subject, search, 0);
3301 if (index == -1) return subject;
3302 *found = true;
3303 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3304 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3305 Handle<String> second =
3306 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3307 return isolate->factory()->NewConsString(cons1, second);
3308 }
3309}
3310
3311
3312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3313 ASSERT(args.length() == 3);
3314 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003315 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3316 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3317 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003318
3319 // If the cons string tree is too deep, we simply abort the recursion and
3320 // retry with a flattened subject string.
3321 const int kRecursionLimit = 0x1000;
3322 bool found = false;
3323 Handle<String> result =
3324 Runtime::StringReplaceOneCharWithString(isolate,
3325 subject,
3326 search,
3327 replace,
3328 &found,
3329 kRecursionLimit);
3330 if (!result.is_null()) return *result;
3331 return *Runtime::StringReplaceOneCharWithString(isolate,
3332 FlattenGetString(subject),
3333 search,
3334 replace,
3335 &found,
3336 kRecursionLimit);
3337}
3338
3339
ager@chromium.org7c537e22008-10-16 08:43:32 +00003340// Perform string match of pattern on subject, starting at start index.
3341// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003342// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343int Runtime::StringMatch(Isolate* isolate,
3344 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003345 Handle<String> pat,
3346 int start_index) {
3347 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003348 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003350 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003351 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003353 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 if (start_index + pattern_length > subject_length) return -1;
3355
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003356 if (!sub->IsFlat()) FlattenString(sub);
3357 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003358
ager@chromium.org7c537e22008-10-16 08:43:32 +00003359 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003360 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003361 String::FlatContent seq_sub = sub->GetFlatContent();
3362 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003363
ager@chromium.org7c537e22008-10-16 08:43:32 +00003364 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 if (seq_pat.IsAscii()) {
3366 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3367 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003369 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003370 pat_vector,
3371 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003372 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 pat_vector,
3376 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003377 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3379 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003381 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 pat_vector,
3383 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003386 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 pat_vector,
3388 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003389}
3390
3391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003392RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394 ASSERT(args.length() == 3);
3395
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003396 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3397 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003399 Object* index = args[2];
3400 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003401 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003402
ager@chromium.org870a0b62008-11-04 11:43:05 +00003403 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 int position =
3405 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003406 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407}
3408
3409
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411static int StringMatchBackwards(Vector<const schar> subject,
3412 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003414 int pattern_length = pattern.length();
3415 ASSERT(pattern_length >= 1);
3416 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417
3418 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 for (int i = 0; i < pattern_length; i++) {
3420 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421 if (c > String::kMaxAsciiCharCode) {
3422 return -1;
3423 }
3424 }
3425 }
3426
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003427 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003428 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003431 while (j < pattern_length) {
3432 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003433 break;
3434 }
3435 j++;
3436 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003437 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003438 return i;
3439 }
3440 }
3441 return -1;
3442}
3443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003445 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 ASSERT(args.length() == 3);
3447
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003448 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3449 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003453 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003455 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003456 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003458 if (start_index + pat_length > sub_length) {
3459 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003460 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 if (pat_length == 0) {
3463 return Smi::FromInt(start_index);
3464 }
3465
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003466 if (!sub->IsFlat()) FlattenString(sub);
3467 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003468
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003469 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003470 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3471
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003472 String::FlatContent sub_content = sub->GetFlatContent();
3473 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003474
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003475 if (pat_content.IsAscii()) {
3476 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3477 if (sub_content.IsAscii()) {
3478 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 pat_vector,
3480 start_index);
3481 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003482 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483 pat_vector,
3484 start_index);
3485 }
3486 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003487 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3488 if (sub_content.IsAscii()) {
3489 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003490 pat_vector,
3491 start_index);
3492 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003493 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003494 pat_vector,
3495 start_index);
3496 }
3497 }
3498
3499 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500}
3501
3502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003503RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003504 NoHandleAllocation ha;
3505 ASSERT(args.length() == 2);
3506
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003507 CONVERT_ARG_CHECKED(String, str1, 0);
3508 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509
3510 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003511 int str1_length = str1->length();
3512 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513
3514 // Decide trivial cases without flattening.
3515 if (str1_length == 0) {
3516 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3517 return Smi::FromInt(-str2_length);
3518 } else {
3519 if (str2_length == 0) return Smi::FromInt(str1_length);
3520 }
3521
3522 int end = str1_length < str2_length ? str1_length : str2_length;
3523
3524 // No need to flatten if we are going to find the answer on the first
3525 // character. At this point we know there is at least one character
3526 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003527 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 if (d != 0) return Smi::FromInt(d);
3529
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003530 str1->TryFlatten();
3531 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 StringInputBuffer& buf1 =
3534 *isolate->runtime_state()->string_locale_compare_buf1();
3535 StringInputBuffer& buf2 =
3536 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
3538 buf1.Reset(str1);
3539 buf2.Reset(str2);
3540
3541 for (int i = 0; i < end; i++) {
3542 uint16_t char1 = buf1.GetNext();
3543 uint16_t char2 = buf2.GetNext();
3544 if (char1 != char2) return Smi::FromInt(char1 - char2);
3545 }
3546
3547 return Smi::FromInt(str1_length - str2_length);
3548}
3549
3550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003551RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 NoHandleAllocation ha;
3553 ASSERT(args.length() == 3);
3554
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003555 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003556 int start, end;
3557 // We have a fast integer-only case here to avoid a conversion to double in
3558 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003559 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3560 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3561 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3562 start = from_number;
3563 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003564 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003565 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3566 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003567 start = FastD2I(from_number);
3568 end = FastD2I(to_number);
3569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 RUNTIME_ASSERT(end >= start);
3571 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003572 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003574 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575}
3576
3577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003578RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 ASSERT_EQ(3, args.length());
3580
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003581 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3582 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3583 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 HandleScope handles;
3585
3586 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3587
3588 if (match.is_null()) {
3589 return Failure::Exception();
3590 }
3591 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 }
3594 int length = subject->length();
3595
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003596 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003597 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003598 int start;
3599 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003601 {
3602 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003603 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003604 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3605 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3606 }
3607 offsets.Add(start);
3608 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 if (start == end) if (++end > length) break;
3610 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003611 if (match.is_null()) {
3612 return Failure::Exception();
3613 }
3614 } while (!match->IsNull());
3615 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003617 Handle<String> substring = isolate->factory()->
3618 NewSubString(subject, offsets.at(0), offsets.at(1));
3619 elements->set(0, *substring);
3620 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003621 int from = offsets.at(i * 2);
3622 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003623 Handle<String> substring = isolate->factory()->
3624 NewProperSubString(subject, from, to);
3625 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003628 result->set_length(Smi::FromInt(matches));
3629 return *result;
3630}
3631
3632
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633// Two smis before and after the match, for very long strings.
3634const int kMaxBuilderEntriesPerRegExpMatch = 5;
3635
3636
3637static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3638 Handle<JSArray> last_match_info,
3639 int match_start,
3640 int match_end) {
3641 // Fill last_match_info with a single capture.
3642 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3643 AssertNoAllocation no_gc;
3644 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3645 RegExpImpl::SetLastCaptureCount(elements, 2);
3646 RegExpImpl::SetLastInput(elements, *subject);
3647 RegExpImpl::SetLastSubject(elements, *subject);
3648 RegExpImpl::SetCapture(elements, 0, match_start);
3649 RegExpImpl::SetCapture(elements, 1, match_end);
3650}
3651
3652
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003653template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654static bool SearchStringMultiple(Isolate* isolate,
3655 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 Vector<const PatternChar> pattern,
3657 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003658 FixedArrayBuilder* builder,
3659 int* match_pos) {
3660 int pos = *match_pos;
3661 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003663 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 while (pos <= max_search_start) {
3666 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3667 *match_pos = pos;
3668 return false;
3669 }
3670 // Position of end of previous match.
3671 int match_end = pos + pattern_length;
3672 int new_pos = search.Search(subject, match_end);
3673 if (new_pos >= 0) {
3674 // A match.
3675 if (new_pos > match_end) {
3676 ReplacementStringBuilder::AddSubjectSlice(builder,
3677 match_end,
3678 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003680 pos = new_pos;
3681 builder->Add(pattern_string);
3682 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003684 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003685 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003686
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 if (pos < max_search_start) {
3688 ReplacementStringBuilder::AddSubjectSlice(builder,
3689 pos + pattern_length,
3690 subject_length);
3691 }
3692 *match_pos = pos;
3693 return true;
3694}
3695
3696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697static bool SearchStringMultiple(Isolate* isolate,
3698 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003699 Handle<String> pattern,
3700 Handle<JSArray> last_match_info,
3701 FixedArrayBuilder* builder) {
3702 ASSERT(subject->IsFlat());
3703 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003704
3705 // Treating as if a previous match was before first character.
3706 int match_pos = -pattern->length();
3707
3708 for (;;) { // Break when search complete.
3709 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3710 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003711 String::FlatContent subject_content = subject->GetFlatContent();
3712 String::FlatContent pattern_content = pattern->GetFlatContent();
3713 if (subject_content.IsAscii()) {
3714 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3715 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003716 if (SearchStringMultiple(isolate,
3717 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003718 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003719 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 builder,
3721 &match_pos)) break;
3722 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 if (SearchStringMultiple(isolate,
3724 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003725 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003726 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003727 builder,
3728 &match_pos)) break;
3729 }
3730 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003731 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3732 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 if (SearchStringMultiple(isolate,
3734 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003735 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003736 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 builder,
3738 &match_pos)) break;
3739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 if (SearchStringMultiple(isolate,
3741 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003742 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003743 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003744 builder,
3745 &match_pos)) break;
3746 }
3747 }
3748 }
3749
3750 if (match_pos >= 0) {
3751 SetLastMatchInfoNoCaptures(subject,
3752 last_match_info,
3753 match_pos,
3754 match_pos + pattern->length());
3755 return true;
3756 }
3757 return false; // No matches at all.
3758}
3759
3760
3761static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003762 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003763 Handle<String> subject,
3764 Handle<JSRegExp> regexp,
3765 Handle<JSArray> last_match_array,
3766 FixedArrayBuilder* builder) {
3767 ASSERT(subject->IsFlat());
3768 int match_start = -1;
3769 int match_end = 0;
3770 int pos = 0;
3771 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3772 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3773
ulan@chromium.org812308e2012-02-29 15:58:45 +00003774 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003775 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003776 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003777 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778
3779 for (;;) { // Break on failure, return on exception.
3780 RegExpImpl::IrregexpResult result =
3781 RegExpImpl::IrregexpExecOnce(regexp,
3782 subject,
3783 pos,
3784 register_vector);
3785 if (result == RegExpImpl::RE_SUCCESS) {
3786 match_start = register_vector[0];
3787 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3788 if (match_end < match_start) {
3789 ReplacementStringBuilder::AddSubjectSlice(builder,
3790 match_end,
3791 match_start);
3792 }
3793 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003795 if (!first) {
3796 builder->Add(*isolate->factory()->NewProperSubString(subject,
3797 match_start,
3798 match_end));
3799 } else {
3800 builder->Add(*isolate->factory()->NewSubString(subject,
3801 match_start,
3802 match_end));
3803 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003804 if (match_start != match_end) {
3805 pos = match_end;
3806 } else {
3807 pos = match_end + 1;
3808 if (pos > subject_length) break;
3809 }
3810 } else if (result == RegExpImpl::RE_FAILURE) {
3811 break;
3812 } else {
3813 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3814 return result;
3815 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003816 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 }
3818
3819 if (match_start >= 0) {
3820 if (match_end < subject_length) {
3821 ReplacementStringBuilder::AddSubjectSlice(builder,
3822 match_end,
3823 subject_length);
3824 }
3825 SetLastMatchInfoNoCaptures(subject,
3826 last_match_array,
3827 match_start,
3828 match_end);
3829 return RegExpImpl::RE_SUCCESS;
3830 } else {
3831 return RegExpImpl::RE_FAILURE; // No matches at all.
3832 }
3833}
3834
3835
3836static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 Handle<String> subject,
3839 Handle<JSRegExp> regexp,
3840 Handle<JSArray> last_match_array,
3841 FixedArrayBuilder* builder) {
3842
3843 ASSERT(subject->IsFlat());
3844 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3845 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3846
ulan@chromium.org812308e2012-02-29 15:58:45 +00003847 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003848 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003849
3850 RegExpImpl::IrregexpResult result =
3851 RegExpImpl::IrregexpExecOnce(regexp,
3852 subject,
3853 0,
3854 register_vector);
3855
3856 int capture_count = regexp->CaptureCount();
3857 int subject_length = subject->length();
3858
3859 // Position to search from.
3860 int pos = 0;
3861 // End of previous match. Differs from pos if match was empty.
3862 int match_end = 0;
3863 if (result == RegExpImpl::RE_SUCCESS) {
3864 // Need to keep a copy of the previous match for creating last_match_info
3865 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003866 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003867 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003868 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869 do {
3870 int match_start = register_vector[0];
3871 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3872 if (match_end < match_start) {
3873 ReplacementStringBuilder::AddSubjectSlice(builder,
3874 match_end,
3875 match_start);
3876 }
3877 match_end = register_vector[1];
3878
3879 {
3880 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003881 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003882 // Arguments array to replace function is match, captures, index and
3883 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 Handle<FixedArray> elements =
3885 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003886 Handle<String> match;
3887 if (!first) {
3888 match = isolate->factory()->NewProperSubString(subject,
3889 match_start,
3890 match_end);
3891 } else {
3892 match = isolate->factory()->NewSubString(subject,
3893 match_start,
3894 match_end);
3895 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003897 for (int i = 1; i <= capture_count; i++) {
3898 int start = register_vector[i * 2];
3899 if (start >= 0) {
3900 int end = register_vector[i * 2 + 1];
3901 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003902 Handle<String> substring;
3903 if (!first) {
3904 substring = isolate->factory()->NewProperSubString(subject,
3905 start,
3906 end);
3907 } else {
3908 substring = isolate->factory()->NewSubString(subject, start, end);
3909 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003910 elements->set(i, *substring);
3911 } else {
3912 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003913 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915 }
3916 elements->set(capture_count + 1, Smi::FromInt(match_start));
3917 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003918 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 // Swap register vectors, so the last successful match is in
3921 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003922 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 prev_register_vector = register_vector;
3924 register_vector = tmp;
3925
3926 if (match_end > match_start) {
3927 pos = match_end;
3928 } else {
3929 pos = match_end + 1;
3930 if (pos > subject_length) {
3931 break;
3932 }
3933 }
3934
3935 result = RegExpImpl::IrregexpExecOnce(regexp,
3936 subject,
3937 pos,
3938 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003939 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003940 } while (result == RegExpImpl::RE_SUCCESS);
3941
3942 if (result != RegExpImpl::RE_EXCEPTION) {
3943 // Finished matching, with at least one match.
3944 if (match_end < subject_length) {
3945 ReplacementStringBuilder::AddSubjectSlice(builder,
3946 match_end,
3947 subject_length);
3948 }
3949
3950 int last_match_capture_count = (capture_count + 1) * 2;
3951 int last_match_array_size =
3952 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3953 last_match_array->EnsureSize(last_match_array_size);
3954 AssertNoAllocation no_gc;
3955 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3956 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3957 RegExpImpl::SetLastSubject(elements, *subject);
3958 RegExpImpl::SetLastInput(elements, *subject);
3959 for (int i = 0; i < last_match_capture_count; i++) {
3960 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3961 }
3962 return RegExpImpl::RE_SUCCESS;
3963 }
3964 }
3965 // No matches at all, return failure or exception result directly.
3966 return result;
3967}
3968
3969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003970RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003971 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003973
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003974 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003975 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003976 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3977 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3978 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003979
3980 ASSERT(last_match_info->HasFastElements());
3981 ASSERT(regexp->GetFlags().is_global());
3982 Handle<FixedArray> result_elements;
3983 if (result_array->HasFastElements()) {
3984 result_elements =
3985 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003986 }
3987 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003989 }
3990 FixedArrayBuilder builder(result_elements);
3991
3992 if (regexp->TypeTag() == JSRegExp::ATOM) {
3993 Handle<String> pattern(
3994 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003995 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 if (SearchStringMultiple(isolate, subject, pattern,
3997 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 return *builder.ToJSArray(result_array);
3999 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004001 }
4002
4003 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4004
4005 RegExpImpl::IrregexpResult result;
4006 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 result = SearchRegExpNoCaptureMultiple(isolate,
4008 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004009 regexp,
4010 last_match_info,
4011 &builder);
4012 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 result = SearchRegExpMultiple(isolate,
4014 subject,
4015 regexp,
4016 last_match_info,
4017 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 }
4019 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004021 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4022 return Failure::Exception();
4023}
4024
4025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004026RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 NoHandleAllocation ha;
4028 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004029 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004030 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004032 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004033 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004034 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004035 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004036 // Character array used for conversion.
4037 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 return isolate->heap()->
4039 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004040 }
4041 }
4042
4043 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004044 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004046 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 }
4048 if (isinf(value)) {
4049 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004050 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 MaybeObject* result =
4056 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 DeleteArray(str);
4058 return result;
4059}
4060
4061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004062RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 NoHandleAllocation ha;
4064 ASSERT(args.length() == 2);
4065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004066 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004068 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070 if (isinf(value)) {
4071 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004076 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 int f = FastD2I(f_number);
4078 RUNTIME_ASSERT(f >= 0);
4079 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 MaybeObject* res =
4081 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084}
4085
4086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 NoHandleAllocation ha;
4089 ASSERT(args.length() == 2);
4090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004091 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004093 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095 if (isinf(value)) {
4096 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004097 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004099 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004101 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 int f = FastD2I(f_number);
4103 RUNTIME_ASSERT(f >= -1 && f <= 20);
4104 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105 MaybeObject* res =
4106 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109}
4110
4111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004112RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 NoHandleAllocation ha;
4114 ASSERT(args.length() == 2);
4115
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004116 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004118 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 }
4120 if (isinf(value)) {
4121 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004122 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004124 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004126 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 int f = FastD2I(f_number);
4128 RUNTIME_ASSERT(f >= 1 && f <= 21);
4129 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004130 MaybeObject* res =
4131 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004133 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134}
4135
4136
4137// Returns a single character string where first character equals
4138// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004140 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004141 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004142 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004143 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004145 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146}
4147
4148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4150 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Handle [] indexing on Strings
4153 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4155 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 }
4157
4158 // Handle [] indexing on String objects
4159 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004160 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4161 Handle<Object> result =
4162 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4163 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
4165
4166 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004167 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169
4170 return object->GetElement(index);
4171}
4172
4173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4175 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004180 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 isolate->factory()->NewTypeError("non_object_property_load",
4183 HandleVector(args, 2));
4184 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
4186
4187 // Check if the given key is an array index.
4188 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004189 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 }
4192
4193 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 bool has_pending_exception = false;
4199 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
4204
ager@chromium.org32912102009-01-16 10:38:43 +00004205 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 // the element if so.
4207 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004210 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 }
4212}
4213
4214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 NoHandleAllocation ha;
4217 ASSERT(args.length() == 2);
4218
4219 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004220 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004222 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223}
4224
4225
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004226// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004227RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004228 NoHandleAllocation ha;
4229 ASSERT(args.length() == 2);
4230
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004232 // itself.
4233 //
4234 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004235 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004236 // global proxy object never has properties. This is the case
4237 // because the global proxy object forwards everything to its hidden
4238 // prototype including local lookups.
4239 //
4240 // Additionally, we need to make sure that we do not cache results
4241 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004242 if (args[0]->IsJSObject()) {
4243 if (!args[0]->IsJSGlobalProxy() &&
4244 !args[0]->IsAccessCheckNeeded() &&
4245 args[1]->IsString()) {
4246 JSObject* receiver = JSObject::cast(args[0]);
4247 String* key = String::cast(args[1]);
4248 if (receiver->HasFastProperties()) {
4249 // Attempt to use lookup cache.
4250 Map* receiver_map = receiver->map();
4251 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4252 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4253 if (offset != -1) {
4254 Object* value = receiver->FastPropertyAt(offset);
4255 return value->IsTheHole()
4256 ? isolate->heap()->undefined_value()
4257 : value;
4258 }
4259 // Lookup cache miss. Perform lookup and update the cache if
4260 // appropriate.
4261 LookupResult result(isolate);
4262 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004263 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004264 int offset = result.GetFieldIndex();
4265 keyed_lookup_cache->Update(receiver_map, key, offset);
4266 return receiver->FastPropertyAt(offset);
4267 }
4268 } else {
4269 // Attempt dictionary lookup.
4270 StringDictionary* dictionary = receiver->property_dictionary();
4271 int entry = dictionary->FindEntry(key);
4272 if ((entry != StringDictionary::kNotFound) &&
4273 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4274 Object* value = dictionary->ValueAt(entry);
4275 if (!receiver->IsGlobalObject()) return value;
4276 value = JSGlobalPropertyCell::cast(value)->value();
4277 if (!value->IsTheHole()) return value;
4278 // If value is the hole do the general lookup.
4279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004280 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004281 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4282 // JSObject without a string key. If the key is a Smi, check for a
4283 // definite out-of-bounds access to elements, which is a strong indicator
4284 // that subsequent accesses will also call the runtime. Proactively
4285 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4286 // doubles for those future calls in the case that the elements would
4287 // become FAST_DOUBLE_ELEMENTS.
4288 Handle<JSObject> js_object(args.at<JSObject>(0));
4289 ElementsKind elements_kind = js_object->GetElementsKind();
4290 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4291 elements_kind == FAST_DOUBLE_ELEMENTS) {
4292 FixedArrayBase* elements = js_object->elements();
4293 if (args.at<Smi>(1)->value() >= elements->length()) {
4294 MaybeObject* maybe_object = TransitionElements(js_object,
4295 FAST_ELEMENTS,
4296 isolate);
4297 if (maybe_object->IsFailure()) return maybe_object;
4298 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004299 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004300 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004301 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4302 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004303 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004304 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004305 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004306 if (index >= 0 && index < str->length()) {
4307 Handle<Object> result = GetCharAt(str, index);
4308 return *result;
4309 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004310 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004311
4312 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 return Runtime::GetObjectProperty(isolate,
4314 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004315 args.at<Object>(1));
4316}
4317
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004318
4319static bool IsValidAccessor(Handle<Object> obj) {
4320 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4321}
4322
4323
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004324// Implements part of 8.12.9 DefineOwnProperty.
4325// There are 3 cases that lead here:
4326// Step 4b - define a new accessor property.
4327// Steps 9c & 12 - replace an existing data property with an accessor property.
4328// Step 12 - update an existing accessor property with an accessor or generic
4329// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004330RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004331 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004332 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004333 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004334 RUNTIME_ASSERT(!obj->IsNull());
4335 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4336 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4337 RUNTIME_ASSERT(IsValidAccessor(getter));
4338 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4339 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004340 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004341 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004342 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004343
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004344 // TODO(svenpanne) Define getter/setter/attributes in a single step.
4345 if (getter->IsNull() && setter->IsNull()) {
4346 JSArray* array;
4347 { MaybeObject* maybe_array = GetOwnProperty(isolate, obj, name);
4348 if (!maybe_array->To(&array)) return maybe_array;
4349 }
4350 Object* current = FixedArray::cast(array->elements())->get(GETTER_INDEX);
4351 getter = Handle<Object>(current, isolate);
4352 }
4353 if (!getter->IsNull()) {
4354 MaybeObject* ok =
4355 obj->DefineAccessor(*name, ACCESSOR_GETTER, *getter, attr);
4356 if (ok->IsFailure()) return ok;
4357 }
4358 if (!setter->IsNull()) {
4359 MaybeObject* ok =
4360 obj->DefineAccessor(*name, ACCESSOR_SETTER, *setter, attr);
4361 if (ok->IsFailure()) return ok;
4362 }
4363
4364 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004365}
4366
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004367// Implements part of 8.12.9 DefineOwnProperty.
4368// There are 3 cases that lead here:
4369// Step 4a - define a new data property.
4370// Steps 9b & 12 - replace an existing accessor property with a data property.
4371// Step 12 - update an existing data property with a data or generic
4372// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004373RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004374 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004376 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4377 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004378 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004379 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004380 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004381 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4382
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004383 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004384 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004385
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004386 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004387 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004388 Object* callback = result.GetCallbackObject();
4389 // To be compatible with Safari we do not change the value on API objects
4390 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4391 // the value.
4392 if (callback->IsAccessorInfo()) {
4393 return isolate->heap()->undefined_value();
4394 }
4395 // Avoid redefining foreign callback as data property, just use the stored
4396 // setter to update the value instead.
4397 // TODO(mstarzinger): So far this only works if property attributes don't
4398 // change, this should be fixed once we cleanup the underlying code.
4399 if (callback->IsForeign() && result.GetAttributes() == attr) {
4400 return js_object->SetPropertyWithCallback(callback,
4401 *name,
4402 *obj_value,
4403 result.holder(),
4404 kStrictMode);
4405 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004406 }
4407
ager@chromium.org5c838252010-02-19 08:53:10 +00004408 // Take special care when attributes are different and there is already
4409 // a property. For simplicity we normalize the property which enables us
4410 // to not worry about changing the instance_descriptor and creating a new
4411 // map. The current version of SetObjectProperty does not handle attributes
4412 // correctly in the case where a property is a field and is reset with
4413 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004414 if (result.IsProperty() &&
4415 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004416 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004417 if (js_object->IsJSGlobalProxy()) {
4418 // Since the result is a property, the prototype will exist so
4419 // we don't have to check for null.
4420 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004421 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004422 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004423 // Use IgnoreAttributes version since a readonly property may be
4424 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004425 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4426 *obj_value,
4427 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004428 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 return Runtime::ForceSetObjectProperty(isolate,
4431 js_object,
4432 name,
4433 obj_value,
4434 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004435}
4436
4437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004438MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4439 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004440 Handle<Object> key,
4441 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004442 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004443 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004444 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004445 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004446
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004448 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 isolate->factory()->NewTypeError("non_object_property_store",
4451 HandleVector(args, 2));
4452 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453 }
4454
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004455 if (object->IsJSProxy()) {
4456 bool has_pending_exception = false;
4457 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4458 if (has_pending_exception) return Failure::Exception();
4459 return JSProxy::cast(*object)->SetProperty(
4460 String::cast(*name), *value, attr, strict_mode);
4461 }
4462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 // If the object isn't a JavaScript object, we ignore the store.
4464 if (!object->IsJSObject()) return *value;
4465
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 // Check if the given key is an array index.
4469 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004470 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4472 // of a string using [] notation. We need to support this too in
4473 // JavaScript.
4474 // In the case of a String object we just need to redirect the assignment to
4475 // the underlying string if the index is in range. Since the underlying
4476 // string does nothing with the assignment then we can ignore such
4477 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004478 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004482 Handle<Object> result = JSObject::SetElement(
4483 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 return *value;
4486 }
4487
4488 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004489 Handle<Object> result;
4490 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004491 result = JSObject::SetElement(
4492 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004494 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004495 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004496 result = JSReceiver::SetProperty(
4497 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004499 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 return *value;
4501 }
4502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 bool has_pending_exception = false;
4505 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4506 if (has_pending_exception) return Failure::Exception();
4507 Handle<String> name = Handle<String>::cast(converted);
4508
4509 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004510 return js_object->SetElement(
4511 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004513 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004514 }
4515}
4516
4517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004518MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4519 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004520 Handle<Object> key,
4521 Handle<Object> value,
4522 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004523 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004524
4525 // Check if the given key is an array index.
4526 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004527 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004528 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4529 // of a string using [] notation. We need to support this too in
4530 // JavaScript.
4531 // In the case of a String object we just need to redirect the assignment to
4532 // the underlying string if the index is in range. Since the underlying
4533 // string does nothing with the assignment then we can ignore such
4534 // assignments.
4535 if (js_object->IsStringObjectWithCharacterAt(index)) {
4536 return *value;
4537 }
4538
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004539 return js_object->SetElement(
4540 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004541 }
4542
4543 if (key->IsString()) {
4544 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004545 return js_object->SetElement(
4546 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004547 } else {
4548 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004549 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004550 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4551 *value,
4552 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004553 }
4554 }
4555
4556 // Call-back into JavaScript to convert the key to a string.
4557 bool has_pending_exception = false;
4558 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4559 if (has_pending_exception) return Failure::Exception();
4560 Handle<String> name = Handle<String>::cast(converted);
4561
4562 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004563 return js_object->SetElement(
4564 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004565 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004566 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004567 }
4568}
4569
4570
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004572 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004573 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004575
4576 // Check if the given key is an array index.
4577 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004578 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004579 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4580 // characters of a string using [] notation. In the case of a
4581 // String object we just need to redirect the deletion to the
4582 // underlying string if the index is in range. Since the
4583 // underlying string does nothing with the deletion, we can ignore
4584 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004585 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004586 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004587 }
4588
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004589 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004590 }
4591
4592 Handle<String> key_string;
4593 if (key->IsString()) {
4594 key_string = Handle<String>::cast(key);
4595 } else {
4596 // Call-back into JavaScript to convert the key to a string.
4597 bool has_pending_exception = false;
4598 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4599 if (has_pending_exception) return Failure::Exception();
4600 key_string = Handle<String>::cast(converted);
4601 }
4602
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004603 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004604 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004605}
4606
4607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004608RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004610 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611
4612 Handle<Object> object = args.at<Object>(0);
4613 Handle<Object> key = args.at<Object>(1);
4614 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004615 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004616 RUNTIME_ASSERT(
4617 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004619 PropertyAttributes attributes =
4620 static_cast<PropertyAttributes>(unchecked_attributes);
4621
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004622 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004623 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004624 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004625 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004628 return Runtime::SetObjectProperty(isolate,
4629 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004630 key,
4631 value,
4632 attributes,
4633 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634}
4635
4636
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4642}
4643
4644
4645RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4646 NoHandleAllocation ha;
4647 RUNTIME_ASSERT(args.length() == 1);
4648 Handle<Object> object = args.at<Object>(0);
4649 return TransitionElements(object, FAST_ELEMENTS, isolate);
4650}
4651
4652
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004653// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004654// This is used to decide if we should transform null and undefined
4655// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004656RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004657 NoHandleAllocation ha;
4658 RUNTIME_ASSERT(args.length() == 1);
4659
4660 Handle<Object> object = args.at<Object>(0);
4661
4662 if (object->IsJSFunction()) {
4663 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004664 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004665 }
4666 return isolate->heap()->undefined_value();
4667}
4668
4669
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004670RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4671 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004672 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004673 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4674 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004675 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004676 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4677 HandleScope scope;
4678
4679 Object* raw_boilerplate_object = literals->get(literal_index);
4680 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4681#if DEBUG
4682 ElementsKind elements_kind = object->GetElementsKind();
4683#endif
4684 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4685 // Smis should never trigger transitions.
4686 ASSERT(!value->IsSmi());
4687
4688 if (value->IsNumber()) {
4689 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004690 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4691 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004692 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4693 FixedDoubleArray* double_array =
4694 FixedDoubleArray::cast(object->elements());
4695 HeapNumber* number = HeapNumber::cast(*value);
4696 double_array->set(store_index, number->Number());
4697 } else {
4698 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4699 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004700 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4701 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004702 FixedArray* object_array =
4703 FixedArray::cast(object->elements());
4704 object_array->set(store_index, *value);
4705 }
4706 return *object;
4707}
4708
4709
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710// Set a local property, even if it is READ_ONLY. If the property does not
4711// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004712RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004714 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004715 CONVERT_ARG_CHECKED(JSObject, object, 0);
4716 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004717 // Compute attributes.
4718 PropertyAttributes attributes = NONE;
4719 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004720 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004721 // Only attribute bits should be set.
4722 RUNTIME_ASSERT(
4723 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4724 attributes = static_cast<PropertyAttributes>(unchecked_value);
4725 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004727 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004728 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729}
4730
4731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004734 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004736 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4737 CONVERT_ARG_CHECKED(String, key, 1);
4738 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004739 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004740 ? JSReceiver::STRICT_DELETION
4741 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742}
4743
4744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745static Object* HasLocalPropertyImplementation(Isolate* isolate,
4746 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004747 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004749 // Handle hidden prototypes. If there's a hidden prototype above this thing
4750 // then we have to check it for properties, because they are supposed to
4751 // look like they are on this object.
4752 Handle<Object> proto(object->GetPrototype());
4753 if (proto->IsJSObject() &&
4754 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return HasLocalPropertyImplementation(isolate,
4756 Handle<JSObject>::cast(proto),
4757 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004758 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004759 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004760}
4761
4762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004763RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 NoHandleAllocation ha;
4765 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004766 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004768 uint32_t index;
4769 const bool key_is_array_index = key->AsArrayIndex(&index);
4770
ager@chromium.org9085a012009-05-11 19:22:57 +00004771 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004773 if (obj->IsJSObject()) {
4774 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004775 // Fast case: either the key is a real named property or it is not
4776 // an array index and there are no interceptors or hidden
4777 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004779 Map* map = object->map();
4780 if (!key_is_array_index &&
4781 !map->has_named_interceptor() &&
4782 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4783 return isolate->heap()->false_value();
4784 }
4785 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004786 HandleScope scope(isolate);
4787 return HasLocalPropertyImplementation(isolate,
4788 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004789 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004790 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004792 String* string = String::cast(obj);
4793 if (index < static_cast<uint32_t>(string->length())) {
4794 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 }
4796 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004797 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798}
4799
4800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004801RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 NoHandleAllocation na;
4803 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004804 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4805 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004807 bool result = receiver->HasProperty(key);
4808 if (isolate->has_pending_exception()) return Failure::Exception();
4809 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810}
4811
4812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004813RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 NoHandleAllocation na;
4815 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004816 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4817 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004819 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004820 if (isolate->has_pending_exception()) return Failure::Exception();
4821 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822}
4823
4824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004825RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 NoHandleAllocation ha;
4827 ASSERT(args.length() == 2);
4828
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004829 CONVERT_ARG_CHECKED(JSObject, object, 0);
4830 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831
4832 uint32_t index;
4833 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004834 JSObject::LocalElementType type = object->HasLocalElement(index);
4835 switch (type) {
4836 case JSObject::UNDEFINED_ELEMENT:
4837 case JSObject::STRING_CHARACTER_ELEMENT:
4838 return isolate->heap()->false_value();
4839 case JSObject::INTERCEPTED_ELEMENT:
4840 case JSObject::FAST_ELEMENT:
4841 return isolate->heap()->true_value();
4842 case JSObject::DICTIONARY_ELEMENT: {
4843 if (object->IsJSGlobalProxy()) {
4844 Object* proto = object->GetPrototype();
4845 if (proto->IsNull()) {
4846 return isolate->heap()->false_value();
4847 }
4848 ASSERT(proto->IsJSGlobalObject());
4849 object = JSObject::cast(proto);
4850 }
4851 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004852 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004853 if (elements->map() ==
4854 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004855 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004856 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004857 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004858 }
4859 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004860 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004861 PropertyDetails details = dictionary->DetailsAt(entry);
4862 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4863 }
4864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 }
4866
ager@chromium.org870a0b62008-11-04 11:43:05 +00004867 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869}
4870
4871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004872RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004875 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004876 bool threw = false;
4877 Handle<JSArray> result = GetKeysFor(object, &threw);
4878 if (threw) return Failure::Exception();
4879 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004880}
4881
4882
4883// Returns either a FixedArray as Runtime_GetPropertyNames,
4884// or, if the given object has an enum cache that contains
4885// all enumerable properties of the object and its prototypes
4886// have none, the map of the object. This is used to speed up
4887// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004888RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889 ASSERT(args.length() == 1);
4890
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004891 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892
4893 if (raw_object->IsSimpleEnum()) return raw_object->map();
4894
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004896 Handle<JSReceiver> object(raw_object);
4897 bool threw = false;
4898 Handle<FixedArray> content =
4899 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4900 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901
4902 // Test again, since cache may have been built by preceding call.
4903 if (object->IsSimpleEnum()) return object->map();
4904
4905 return *content;
4906}
4907
4908
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004909// Find the length of the prototype chain that is to to handled as one. If a
4910// prototype object is hidden it is to be viewed as part of the the object it
4911// is prototype for.
4912static int LocalPrototypeChainLength(JSObject* obj) {
4913 int count = 1;
4914 Object* proto = obj->GetPrototype();
4915 while (proto->IsJSObject() &&
4916 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4917 count++;
4918 proto = JSObject::cast(proto)->GetPrototype();
4919 }
4920 return count;
4921}
4922
4923
4924// Return the names of the local named properties.
4925// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004926RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004927 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004928 ASSERT(args.length() == 1);
4929 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004930 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004932 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004933
4934 // Skip the global proxy as it has no properties and always delegates to the
4935 // real global object.
4936 if (obj->IsJSGlobalProxy()) {
4937 // Only collect names if access is permitted.
4938 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004939 !isolate->MayNamedAccess(*obj,
4940 isolate->heap()->undefined_value(),
4941 v8::ACCESS_KEYS)) {
4942 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4943 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004944 }
4945 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4946 }
4947
4948 // Find the number of objects making up this.
4949 int length = LocalPrototypeChainLength(*obj);
4950
4951 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004952 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004953 int total_property_count = 0;
4954 Handle<JSObject> jsproto = obj;
4955 for (int i = 0; i < length; i++) {
4956 // Only collect names if access is permitted.
4957 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004958 !isolate->MayNamedAccess(*jsproto,
4959 isolate->heap()->undefined_value(),
4960 v8::ACCESS_KEYS)) {
4961 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4962 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963 }
4964 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004965 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004966 local_property_count[i] = n;
4967 total_property_count += n;
4968 if (i < length - 1) {
4969 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4970 }
4971 }
4972
4973 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 Handle<FixedArray> names =
4975 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004976
4977 // Get the property names.
4978 jsproto = obj;
4979 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004980 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004981 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004982 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4983 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004984 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 proto_with_hidden_properties++;
4986 }
4987 if (i < length - 1) {
4988 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4989 }
4990 }
4991
4992 // Filter out name of hidden propeties object.
4993 if (proto_with_hidden_properties > 0) {
4994 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004996 names->length() - proto_with_hidden_properties);
4997 int dest_pos = 0;
4998 for (int i = 0; i < total_property_count; i++) {
4999 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005001 continue;
5002 }
5003 names->set(dest_pos++, name);
5004 }
5005 }
5006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005007 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005008}
5009
5010
5011// Return the names of the local indexed properties.
5012// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005013RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005015 ASSERT(args.length() == 1);
5016 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005017 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005018 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005019 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005020
5021 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005022 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005023 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005025}
5026
5027
5028// Return information on whether an object has a named or indexed interceptor.
5029// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005030RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 ASSERT(args.length() == 1);
5033 if (!args[0]->IsJSObject()) {
5034 return Smi::FromInt(0);
5035 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005036 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005037
5038 int result = 0;
5039 if (obj->HasNamedInterceptor()) result |= 2;
5040 if (obj->HasIndexedInterceptor()) result |= 1;
5041
5042 return Smi::FromInt(result);
5043}
5044
5045
5046// Return property names from named interceptor.
5047// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005048RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005050 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005051 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005052
5053 if (obj->HasNamedInterceptor()) {
5054 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5055 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5056 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005058}
5059
5060
5061// Return element names from indexed interceptor.
5062// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005063RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005066 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005067
5068 if (obj->HasIndexedInterceptor()) {
5069 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5070 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5071 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005073}
5074
5075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005076RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005077 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005078 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005080 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005081
5082 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005083 // Do access checks before going to the global object.
5084 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005086 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5088 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005089 }
5090
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005091 Handle<Object> proto(object->GetPrototype());
5092 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005094 object = Handle<JSObject>::cast(proto);
5095 }
5096
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005097 bool threw = false;
5098 Handle<FixedArray> contents =
5099 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5100 if (threw) return Failure::Exception();
5101
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005102 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5103 // property array and since the result is mutable we have to create
5104 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005105 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005107 for (int i = 0; i < length; i++) {
5108 Object* entry = contents->get(i);
5109 if (entry->IsString()) {
5110 copy->set(i, entry);
5111 } else {
5112 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113 HandleScope scope(isolate);
5114 Handle<Object> entry_handle(entry, isolate);
5115 Handle<Object> entry_str =
5116 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005117 copy->set(i, *entry_str);
5118 }
5119 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005120 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005121}
5122
5123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005124RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005125 NoHandleAllocation ha;
5126 ASSERT(args.length() == 1);
5127
5128 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005129 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005130 it.AdvanceToArgumentsFrame();
5131 JavaScriptFrame* frame = it.frame();
5132
5133 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005134 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005135
5136 // Try to convert the key to an index. If successful and within
5137 // index return the the argument from the frame.
5138 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005139 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005140 return frame->GetParameter(index);
5141 }
5142
5143 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005145 bool exception = false;
5146 Handle<Object> converted =
5147 Execution::ToString(args.at<Object>(0), &exception);
5148 if (exception) return Failure::Exception();
5149 Handle<String> key = Handle<String>::cast(converted);
5150
5151 // Try to convert the string key into an array index.
5152 if (key->AsArrayIndex(&index)) {
5153 if (index < n) {
5154 return frame->GetParameter(index);
5155 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005156 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157 }
5158 }
5159
5160 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005161 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5162 if (key->Equals(isolate->heap()->callee_symbol())) {
5163 Object* function = frame->function();
5164 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005165 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 return isolate->Throw(*isolate->factory()->NewTypeError(
5167 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5168 }
5169 return function;
5170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171
5172 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005173 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174}
5175
5176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005177RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005178 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005179 Object* object = args[0];
5180 return (object->IsJSObject() && !object->IsGlobalObject())
5181 ? JSObject::cast(object)->TransformToFastProperties(0)
5182 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005183}
5184
5185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005186RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005187 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005188 Object* obj = args[0];
5189 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5190 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5191 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005192}
5193
5194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005195RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 NoHandleAllocation ha;
5197 ASSERT(args.length() == 1);
5198
5199 return args[0]->ToBoolean();
5200}
5201
5202
5203// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5204// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005205RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 NoHandleAllocation ha;
5207
5208 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 HeapObject* heap_obj = HeapObject::cast(obj);
5211
5212 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 if (heap_obj->map()->is_undetectable()) {
5214 return isolate->heap()->undefined_symbol();
5215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216
5217 InstanceType instance_type = heap_obj->map()->instance_type();
5218 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 }
5221
5222 switch (instance_type) {
5223 case ODDBALL_TYPE:
5224 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 }
5227 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005228 return FLAG_harmony_typeof
5229 ? isolate->heap()->null_symbol()
5230 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005231 }
5232 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005233 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005234 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005235 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 default:
5238 // For any kind of object not handled above, the spec rule for
5239 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 }
5242}
5243
5244
lrn@chromium.org25156de2010-04-06 13:10:27 +00005245static bool AreDigits(const char*s, int from, int to) {
5246 for (int i = from; i < to; i++) {
5247 if (s[i] < '0' || s[i] > '9') return false;
5248 }
5249
5250 return true;
5251}
5252
5253
5254static int ParseDecimalInteger(const char*s, int from, int to) {
5255 ASSERT(to - from < 10); // Overflow is not possible.
5256 ASSERT(from < to);
5257 int d = s[from] - '0';
5258
5259 for (int i = from + 1; i < to; i++) {
5260 d = 10 * d + (s[i] - '0');
5261 }
5262
5263 return d;
5264}
5265
5266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005267RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 NoHandleAllocation ha;
5269 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005270 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005271 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005272
5273 // Fast case: short integer or some sorts of junk values.
5274 int len = subject->length();
5275 if (subject->IsSeqAsciiString()) {
5276 if (len == 0) return Smi::FromInt(0);
5277
5278 char const* data = SeqAsciiString::cast(subject)->GetChars();
5279 bool minus = (data[0] == '-');
5280 int start_pos = (minus ? 1 : 0);
5281
5282 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005284 } else if (data[start_pos] > '9') {
5285 // Fast check for a junk value. A valid string may start from a
5286 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5287 // the 'I' character ('Infinity'). All of that have codes not greater than
5288 // '9' except 'I'.
5289 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005290 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005291 }
5292 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5293 // The maximal/minimal smi has 10 digits. If the string has less digits we
5294 // know it will fit into the smi-data type.
5295 int d = ParseDecimalInteger(data, start_pos, len);
5296 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005297 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005298 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005299 } else if (!subject->HasHashCode() &&
5300 len <= String::kMaxArrayIndexSize &&
5301 (len == 1 || data[0] != '0')) {
5302 // String hash is not calculated yet but all the data are present.
5303 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005304 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005305#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005306 subject->Hash(); // Force hash calculation.
5307 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5308 static_cast<int>(hash));
5309#endif
5310 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005311 }
5312 return Smi::FromInt(d);
5313 }
5314 }
5315
5316 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005317 return isolate->heap()->NumberFromDouble(
5318 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319}
5320
5321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005322RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 NoHandleAllocation ha;
5324 ASSERT(args.length() == 1);
5325
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005326 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 int length = Smi::cast(codes->length())->value();
5328
5329 // Check if the string can be ASCII.
5330 int i;
5331 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005332 Object* element;
5333 { MaybeObject* maybe_element = codes->GetElement(i);
5334 // We probably can't get an exception here, but just in order to enforce
5335 // the checking of inputs in the runtime calls we check here.
5336 if (!maybe_element->ToObject(&element)) return maybe_element;
5337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5339 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5340 break;
5341 }
5342
lrn@chromium.org303ada72010-10-27 09:33:13 +00005343 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005345 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005346 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005347 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005348 }
5349
lrn@chromium.org303ada72010-10-27 09:33:13 +00005350 Object* object = NULL;
5351 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 String* result = String::cast(object);
5353 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005354 Object* element;
5355 { MaybeObject* maybe_element = codes->GetElement(i);
5356 if (!maybe_element->ToObject(&element)) return maybe_element;
5357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005358 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005359 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 }
5361 return result;
5362}
5363
5364
5365// kNotEscaped is generated by the following:
5366//
5367// #!/bin/perl
5368// for (my $i = 0; $i < 256; $i++) {
5369// print "\n" if $i % 16 == 0;
5370// my $c = chr($i);
5371// my $escaped = 1;
5372// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5373// print $escaped ? "0, " : "1, ";
5374// }
5375
5376
5377static bool IsNotEscaped(uint16_t character) {
5378 // Only for 8 bit characters, the rest are always escaped (in a different way)
5379 ASSERT(character < 256);
5380 static const char kNotEscaped[256] = {
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5387 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5388 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5397 };
5398 return kNotEscaped[character] != 0;
5399}
5400
5401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005402RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403 const char hex_chars[] = "0123456789ABCDEF";
5404 NoHandleAllocation ha;
5405 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005406 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005408 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409
5410 int escaped_length = 0;
5411 int length = source->length();
5412 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 Access<StringInputBuffer> buffer(
5414 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 buffer->Reset(source);
5416 while (buffer->has_more()) {
5417 uint16_t character = buffer->GetNext();
5418 if (character >= 256) {
5419 escaped_length += 6;
5420 } else if (IsNotEscaped(character)) {
5421 escaped_length++;
5422 } else {
5423 escaped_length += 3;
5424 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005425 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005426 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005427 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005428 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429 return Failure::OutOfMemoryException();
5430 }
5431 }
5432 }
5433 // No length change implies no change. Return original string if no change.
5434 if (escaped_length == length) {
5435 return source;
5436 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005437 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005438 { MaybeObject* maybe_o =
5439 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005440 if (!maybe_o->ToObject(&o)) return maybe_o;
5441 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005442 String* destination = String::cast(o);
5443 int dest_position = 0;
5444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 Access<StringInputBuffer> buffer(
5446 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 buffer->Rewind();
5448 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005449 uint16_t chr = buffer->GetNext();
5450 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 destination->Set(dest_position, '%');
5452 destination->Set(dest_position+1, 'u');
5453 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5454 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5455 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5456 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005458 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005459 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005460 dest_position++;
5461 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462 destination->Set(dest_position, '%');
5463 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5464 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 dest_position += 3;
5466 }
5467 }
5468 return destination;
5469}
5470
5471
5472static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5473 static const signed char kHexValue['g'] = {
5474 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5475 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5476 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5477 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5478 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5479 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5480 -1, 10, 11, 12, 13, 14, 15 };
5481
5482 if (character1 > 'f') return -1;
5483 int hi = kHexValue[character1];
5484 if (hi == -1) return -1;
5485 if (character2 > 'f') return -1;
5486 int lo = kHexValue[character2];
5487 if (lo == -1) return -1;
5488 return (hi << 4) + lo;
5489}
5490
5491
ager@chromium.org870a0b62008-11-04 11:43:05 +00005492static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005493 int i,
5494 int length,
5495 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005496 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005497 int32_t hi = 0;
5498 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499 if (character == '%' &&
5500 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 source->Get(i + 1) == 'u' &&
5502 (hi = TwoDigitHex(source->Get(i + 2),
5503 source->Get(i + 3))) != -1 &&
5504 (lo = TwoDigitHex(source->Get(i + 4),
5505 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506 *step = 6;
5507 return (hi << 8) + lo;
5508 } else if (character == '%' &&
5509 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005510 (lo = TwoDigitHex(source->Get(i + 1),
5511 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005512 *step = 3;
5513 return lo;
5514 } else {
5515 *step = 1;
5516 return character;
5517 }
5518}
5519
5520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005521RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522 NoHandleAllocation ha;
5523 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005524 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005525
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005526 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527
5528 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005529 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530
5531 int unescaped_length = 0;
5532 for (int i = 0; i < length; unescaped_length++) {
5533 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005534 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537 i += step;
5538 }
5539
5540 // No length change implies no change. Return original string if no change.
5541 if (unescaped_length == length)
5542 return source;
5543
lrn@chromium.org303ada72010-10-27 09:33:13 +00005544 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005545 { MaybeObject* maybe_o =
5546 ascii ?
5547 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5548 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005549 if (!maybe_o->ToObject(&o)) return maybe_o;
5550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551 String* destination = String::cast(o);
5552
5553 int dest_position = 0;
5554 for (int i = 0; i < length; dest_position++) {
5555 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005556 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557 i += step;
5558 }
5559 return destination;
5560}
5561
5562
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005563static const unsigned int kQuoteTableLength = 128u;
5564
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005565static const int kJsonQuotesCharactersPerEntry = 8;
5566static const char* const JsonQuotes =
5567 "\\u0000 \\u0001 \\u0002 \\u0003 "
5568 "\\u0004 \\u0005 \\u0006 \\u0007 "
5569 "\\b \\t \\n \\u000b "
5570 "\\f \\r \\u000e \\u000f "
5571 "\\u0010 \\u0011 \\u0012 \\u0013 "
5572 "\\u0014 \\u0015 \\u0016 \\u0017 "
5573 "\\u0018 \\u0019 \\u001a \\u001b "
5574 "\\u001c \\u001d \\u001e \\u001f "
5575 " ! \\\" # "
5576 "$ % & ' "
5577 "( ) * + "
5578 ", - . / "
5579 "0 1 2 3 "
5580 "4 5 6 7 "
5581 "8 9 : ; "
5582 "< = > ? "
5583 "@ A B C "
5584 "D E F G "
5585 "H I J K "
5586 "L M N O "
5587 "P Q R S "
5588 "T U V W "
5589 "X Y Z [ "
5590 "\\\\ ] ^ _ "
5591 "` a b c "
5592 "d e f g "
5593 "h i j k "
5594 "l m n o "
5595 "p q r s "
5596 "t u v w "
5597 "x y z { "
5598 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005599
5600
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005601// For a string that is less than 32k characters it should always be
5602// possible to allocate it in new space.
5603static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5604
5605
5606// Doing JSON quoting cannot make the string more than this many times larger.
5607static const int kJsonQuoteWorstCaseBlowup = 6;
5608
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005609static const int kSpaceForQuotesAndComma = 3;
5610static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005611
5612// Covers the entire ASCII range (all other characters are unchanged by JSON
5613// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614static const byte JsonQuoteLengths[kQuoteTableLength] = {
5615 6, 6, 6, 6, 6, 6, 6, 6,
5616 2, 2, 2, 6, 2, 2, 6, 6,
5617 6, 6, 6, 6, 6, 6, 6, 6,
5618 6, 6, 6, 6, 6, 6, 6, 6,
5619 1, 1, 2, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 1, 1, 1, 1,
5623 1, 1, 1, 1, 1, 1, 1, 1,
5624 1, 1, 1, 1, 1, 1, 1, 1,
5625 1, 1, 1, 1, 1, 1, 1, 1,
5626 1, 1, 1, 1, 2, 1, 1, 1,
5627 1, 1, 1, 1, 1, 1, 1, 1,
5628 1, 1, 1, 1, 1, 1, 1, 1,
5629 1, 1, 1, 1, 1, 1, 1, 1,
5630 1, 1, 1, 1, 1, 1, 1, 1,
5631};
5632
5633
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005634template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636
5637
5638template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005639MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5640 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005641}
5642
5643
5644template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005645MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5646 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005647}
5648
5649
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005650template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005651static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5652 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005653 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005654 const Char* read_cursor = characters.start();
5655 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005656 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005657 int quoted_length = kSpaceForQuotes;
5658 while (read_cursor < end) {
5659 Char c = *(read_cursor++);
5660 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5661 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005663 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664 }
5665 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005666 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5667 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668 Object* new_object;
5669 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005670 return new_alloc;
5671 }
5672 StringType* new_string = StringType::cast(new_object);
5673
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005674 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005675 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005676 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005677 *(write_cursor++) = '"';
5678
5679 read_cursor = characters.start();
5680 while (read_cursor < end) {
5681 Char c = *(read_cursor++);
5682 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5683 *(write_cursor++) = c;
5684 } else {
5685 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5686 const char* replacement = JsonQuotes +
5687 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5688 for (int i = 0; i < len; i++) {
5689 *write_cursor++ = *replacement++;
5690 }
5691 }
5692 }
5693 *(write_cursor++) = '"';
5694 return new_string;
5695}
5696
5697
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005698template <typename SinkChar, typename SourceChar>
5699static inline SinkChar* WriteQuoteJsonString(
5700 Isolate* isolate,
5701 SinkChar* write_cursor,
5702 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005703 // SinkChar is only char if SourceChar is guaranteed to be char.
5704 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005705 const SourceChar* read_cursor = characters.start();
5706 const SourceChar* end = read_cursor + characters.length();
5707 *(write_cursor++) = '"';
5708 while (read_cursor < end) {
5709 SourceChar c = *(read_cursor++);
5710 if (sizeof(SourceChar) > 1u &&
5711 static_cast<unsigned>(c) >= kQuoteTableLength) {
5712 *(write_cursor++) = static_cast<SinkChar>(c);
5713 } else {
5714 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5715 const char* replacement = JsonQuotes +
5716 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5717 write_cursor[0] = replacement[0];
5718 if (len > 1) {
5719 write_cursor[1] = replacement[1];
5720 if (len > 2) {
5721 ASSERT(len == 6);
5722 write_cursor[2] = replacement[2];
5723 write_cursor[3] = replacement[3];
5724 write_cursor[4] = replacement[4];
5725 write_cursor[5] = replacement[5];
5726 }
5727 }
5728 write_cursor += len;
5729 }
5730 }
5731 *(write_cursor++) = '"';
5732 return write_cursor;
5733}
5734
5735
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005736template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005737static MaybeObject* QuoteJsonString(Isolate* isolate,
5738 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005739 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005740 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005741 int worst_case_length =
5742 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005743 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005744 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005745 }
5746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005747 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5748 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005749 Object* new_object;
5750 if (!new_alloc->ToObject(&new_object)) {
5751 return new_alloc;
5752 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005754 // Even if our string is small enough to fit in new space we still have to
5755 // handle it being allocated in old space as may happen in the third
5756 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5757 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005758 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005759 }
5760 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005761 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005762
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005763 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005764 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005765 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005766 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5767 write_cursor,
5768 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005769 int final_length = static_cast<int>(
5770 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005771 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005772 isolate->heap()->new_space()->
5773 template ShrinkStringAtAllocationBoundary<StringType>(
5774 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005775 return new_string;
5776}
5777
5778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005779RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005780 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005781 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005782 if (!str->IsFlat()) {
5783 MaybeObject* try_flatten = str->TryFlatten();
5784 Object* flat;
5785 if (!try_flatten->ToObject(&flat)) {
5786 return try_flatten;
5787 }
5788 str = String::cast(flat);
5789 ASSERT(str->IsFlat());
5790 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005791 String::FlatContent flat = str->GetFlatContent();
5792 ASSERT(flat.IsFlat());
5793 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005794 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005795 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005796 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005798 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005799 }
5800}
5801
5802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005803RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005804 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005805 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005806 if (!str->IsFlat()) {
5807 MaybeObject* try_flatten = str->TryFlatten();
5808 Object* flat;
5809 if (!try_flatten->ToObject(&flat)) {
5810 return try_flatten;
5811 }
5812 str = String::cast(flat);
5813 ASSERT(str->IsFlat());
5814 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005815 String::FlatContent flat = str->GetFlatContent();
5816 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005817 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005818 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005819 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005821 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005822 }
5823}
5824
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005825
5826template <typename Char, typename StringType>
5827static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5828 FixedArray* array,
5829 int worst_case_length) {
5830 int length = array->length();
5831
5832 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5833 worst_case_length);
5834 Object* new_object;
5835 if (!new_alloc->ToObject(&new_object)) {
5836 return new_alloc;
5837 }
5838 if (!isolate->heap()->new_space()->Contains(new_object)) {
5839 // Even if our string is small enough to fit in new space we still have to
5840 // handle it being allocated in old space as may happen in the third
5841 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5842 // CEntryStub::GenerateCore.
5843 return isolate->heap()->undefined_value();
5844 }
5845 AssertNoAllocation no_gc;
5846 StringType* new_string = StringType::cast(new_object);
5847 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5848
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005849 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005850 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005851 *(write_cursor++) = '[';
5852 for (int i = 0; i < length; i++) {
5853 if (i != 0) *(write_cursor++) = ',';
5854 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005855 String::FlatContent content = str->GetFlatContent();
5856 ASSERT(content.IsFlat());
5857 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005858 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5859 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005860 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005861 } else {
5862 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5863 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005864 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005865 }
5866 }
5867 *(write_cursor++) = ']';
5868
5869 int final_length = static_cast<int>(
5870 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005871 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005872 isolate->heap()->new_space()->
5873 template ShrinkStringAtAllocationBoundary<StringType>(
5874 new_string, final_length);
5875 return new_string;
5876}
5877
5878
5879RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5880 NoHandleAllocation ha;
5881 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005882 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005883
5884 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5885 FixedArray* elements = FixedArray::cast(array->elements());
5886 int n = elements->length();
5887 bool ascii = true;
5888 int total_length = 0;
5889
5890 for (int i = 0; i < n; i++) {
5891 Object* elt = elements->get(i);
5892 if (!elt->IsString()) return isolate->heap()->undefined_value();
5893 String* element = String::cast(elt);
5894 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5895 total_length += element->length();
5896 if (ascii && element->IsTwoByteRepresentation()) {
5897 ascii = false;
5898 }
5899 }
5900
5901 int worst_case_length =
5902 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5903 + total_length * kJsonQuoteWorstCaseBlowup;
5904
5905 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5906 return isolate->heap()->undefined_value();
5907 }
5908
5909 if (ascii) {
5910 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5911 elements,
5912 worst_case_length);
5913 } else {
5914 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5915 elements,
5916 worst_case_length);
5917 }
5918}
5919
5920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005921RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922 NoHandleAllocation ha;
5923
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005924 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005925 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005927 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928
lrn@chromium.org25156de2010-04-06 13:10:27 +00005929 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005930 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932}
5933
5934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005935RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005937 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
5939 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005940 double value = StringToDouble(isolate->unicode_cache(),
5941 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942
5943 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005944 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945}
5946
5947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005949MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005951 String* s,
5952 int length,
5953 int input_string_length,
5954 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005955 // We try this twice, once with the assumption that the result is no longer
5956 // than the input and, if that assumption breaks, again with the exact
5957 // length. This may not be pretty, but it is nicer than what was here before
5958 // and I hereby claim my vaffel-is.
5959 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960 // Allocate the resulting string.
5961 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005962 // NOTE: This assumes that the upper/lower case of an ASCII
5963 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 // might break in the future if we implement more context and locale
5965 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005966 Object* o;
5967 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005968 ? isolate->heap()->AllocateRawAsciiString(length)
5969 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005970 if (!maybe_o->ToObject(&o)) return maybe_o;
5971 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972 String* result = String::cast(o);
5973 bool has_changed_character = false;
5974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 // Convert all characters to upper case, assuming that they will fit
5976 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005977 Access<StringInputBuffer> buffer(
5978 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005980 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 // We can assume that the string is not empty
5982 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005983 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005984 bool has_next = buffer->has_more();
5985 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 int char_length = mapping->get(current, next, chars);
5987 if (char_length == 0) {
5988 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005989 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 i++;
5991 } else if (char_length == 1) {
5992 // Common case: converting the letter resulted in one character.
5993 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005994 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 has_changed_character = true;
5996 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005997 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 // We've assumed that the result would be as long as the
5999 // input but here is a character that converts to several
6000 // characters. No matter, we calculate the exact length
6001 // of the result and try the whole thing again.
6002 //
6003 // Note that this leaves room for optimization. We could just
6004 // memcpy what we already have to the result string. Also,
6005 // the result string is the last object allocated we could
6006 // "realloc" it and probably, in the vast majority of cases,
6007 // extend the existing string to be able to hold the full
6008 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006009 int next_length = 0;
6010 if (has_next) {
6011 next_length = mapping->get(next, 0, chars);
6012 if (next_length == 0) next_length = 1;
6013 }
6014 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 while (buffer->has_more()) {
6016 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006017 // NOTE: we use 0 as the next character here because, while
6018 // the next character may affect what a character converts to,
6019 // it does not in any case affect the length of what it convert
6020 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 int char_length = mapping->get(current, 0, chars);
6022 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006023 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006024 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006026 return Failure::OutOfMemoryException();
6027 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 // Try again with the real length.
6030 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 } else {
6032 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 i++;
6035 }
6036 has_changed_character = true;
6037 }
6038 current = next;
6039 }
6040 if (has_changed_character) {
6041 return result;
6042 } else {
6043 // If we didn't actually change anything in doing the conversion
6044 // we simple return the result and let the converted string
6045 // become garbage; there is no reason to keep two identical strings
6046 // alive.
6047 return s;
6048 }
6049}
6050
6051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052namespace {
6053
lrn@chromium.org303ada72010-10-27 09:33:13 +00006054static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6055
6056
6057// Given a word and two range boundaries returns a word with high bit
6058// set in every byte iff the corresponding input byte was strictly in
6059// the range (m, n). All the other bits in the result are cleared.
6060// This function is only useful when it can be inlined and the
6061// boundaries are statically known.
6062// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006063// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006064static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006065 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006066 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6067 // Use strict inequalities since in edge cases the function could be
6068 // further simplified.
6069 ASSERT(0 < m && m < n && n < 0x7F);
6070 // Has high bit set in every w byte less than n.
6071 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6072 // Has high bit set in every w byte greater than m.
6073 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6074 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6075}
6076
6077
6078enum AsciiCaseConversion {
6079 ASCII_TO_LOWER,
6080 ASCII_TO_UPPER
6081};
6082
6083
6084template <AsciiCaseConversion dir>
6085struct FastAsciiConverter {
6086 static bool Convert(char* dst, char* src, int length) {
6087#ifdef DEBUG
6088 char* saved_dst = dst;
6089 char* saved_src = src;
6090#endif
6091 // We rely on the distance between upper and lower case letters
6092 // being a known power of 2.
6093 ASSERT('a' - 'A' == (1 << 5));
6094 // Boundaries for the range of input characters than require conversion.
6095 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6096 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6097 bool changed = false;
6098 char* const limit = src + length;
6099#ifdef V8_HOST_CAN_READ_UNALIGNED
6100 // Process the prefix of the input that requires no conversion one
6101 // (machine) word at a time.
6102 while (src <= limit - sizeof(uintptr_t)) {
6103 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6104 if (AsciiRangeMask(w, lo, hi) != 0) {
6105 changed = true;
6106 break;
6107 }
6108 *reinterpret_cast<uintptr_t*>(dst) = w;
6109 src += sizeof(uintptr_t);
6110 dst += sizeof(uintptr_t);
6111 }
6112 // Process the remainder of the input performing conversion when
6113 // required one word at a time.
6114 while (src <= limit - sizeof(uintptr_t)) {
6115 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6116 uintptr_t m = AsciiRangeMask(w, lo, hi);
6117 // The mask has high (7th) bit set in every byte that needs
6118 // conversion and we know that the distance between cases is
6119 // 1 << 5.
6120 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6121 src += sizeof(uintptr_t);
6122 dst += sizeof(uintptr_t);
6123 }
6124#endif
6125 // Process the last few bytes of the input (or the whole input if
6126 // unaligned access is not supported).
6127 while (src < limit) {
6128 char c = *src;
6129 if (lo < c && c < hi) {
6130 c ^= (1 << 5);
6131 changed = true;
6132 }
6133 *dst = c;
6134 ++src;
6135 ++dst;
6136 }
6137#ifdef DEBUG
6138 CheckConvert(saved_dst, saved_src, length, changed);
6139#endif
6140 return changed;
6141 }
6142
6143#ifdef DEBUG
6144 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6145 bool expected_changed = false;
6146 for (int i = 0; i < length; i++) {
6147 if (dst[i] == src[i]) continue;
6148 expected_changed = true;
6149 if (dir == ASCII_TO_LOWER) {
6150 ASSERT('A' <= src[i] && src[i] <= 'Z');
6151 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6152 } else {
6153 ASSERT(dir == ASCII_TO_UPPER);
6154 ASSERT('a' <= src[i] && src[i] <= 'z');
6155 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6156 }
6157 }
6158 ASSERT(expected_changed == changed);
6159 }
6160#endif
6161};
6162
6163
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164struct ToLowerTraits {
6165 typedef unibrow::ToLowercase UnibrowConverter;
6166
lrn@chromium.org303ada72010-10-27 09:33:13 +00006167 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006168};
6169
6170
6171struct ToUpperTraits {
6172 typedef unibrow::ToUppercase UnibrowConverter;
6173
lrn@chromium.org303ada72010-10-27 09:33:13 +00006174 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006175};
6176
6177} // namespace
6178
6179
6180template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006181MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006182 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006183 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006184 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006185 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006186 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006187 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006189 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006190 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006191 if (length == 0) return s;
6192
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006193 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006194 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006195 // NOTE: This assumes that the upper/lower case of an ASCII
6196 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006197 // might break in the future if we implement more context and locale
6198 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006199 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006200 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006202 if (!maybe_o->ToObject(&o)) return maybe_o;
6203 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006204 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006205 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006206 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207 return has_changed_character ? result : s;
6208 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006209
lrn@chromium.org303ada72010-10-27 09:33:13 +00006210 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006211 { MaybeObject* maybe_answer =
6212 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006215 if (answer->IsSmi()) {
6216 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006217 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 ConvertCaseHelper(isolate,
6219 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006220 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6221 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006222 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006223 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006224}
6225
6226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006227RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return ConvertCase<ToLowerTraits>(
6229 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006230}
6231
6232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 return ConvertCase<ToUpperTraits>(
6235 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236}
6237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006238
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006239static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006240 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006241}
6242
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006244RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006245 NoHandleAllocation ha;
6246 ASSERT(args.length() == 3);
6247
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006248 CONVERT_ARG_CHECKED(String, s, 0);
6249 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6250 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006251
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006252 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006253 int length = s->length();
6254
6255 int left = 0;
6256 if (trimLeft) {
6257 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6258 left++;
6259 }
6260 }
6261
6262 int right = length;
6263 if (trimRight) {
6264 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6265 right--;
6266 }
6267 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006268 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006269}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006272RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006274 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006275 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6276 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006277 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6278
6279 int subject_length = subject->length();
6280 int pattern_length = pattern->length();
6281 RUNTIME_ASSERT(pattern_length > 0);
6282
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006283 if (limit == 0xffffffffu) {
6284 Handle<Object> cached_answer(StringSplitCache::Lookup(
6285 isolate->heap()->string_split_cache(),
6286 *subject,
6287 *pattern));
6288 if (*cached_answer != Smi::FromInt(0)) {
6289 Handle<JSArray> result =
6290 isolate->factory()->NewJSArrayWithElements(
6291 Handle<FixedArray>::cast(cached_answer));
6292 return *result;
6293 }
6294 }
6295
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006296 // The limit can be very large (0xffffffffu), but since the pattern
6297 // isn't empty, we can never create more parts than ~half the length
6298 // of the subject.
6299
6300 if (!subject->IsFlat()) FlattenString(subject);
6301
6302 static const int kMaxInitialListCapacity = 16;
6303
danno@chromium.org40cb8782011-05-25 07:58:50 +00006304 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305
6306 // Find (up to limit) indices of separator and end-of-string in subject
6307 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6308 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006309 if (!pattern->IsFlat()) FlattenString(pattern);
6310
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006311 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006312
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006313 if (static_cast<uint32_t>(indices.length()) < limit) {
6314 indices.Add(subject_length);
6315 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006316
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006317 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006318
6319 // Create JSArray of substrings separated by separator.
6320 int part_count = indices.length();
6321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006323 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006324 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006325 result->set_length(Smi::FromInt(part_count));
6326
6327 ASSERT(result->HasFastElements());
6328
6329 if (part_count == 1 && indices.at(0) == subject_length) {
6330 FixedArray::cast(result->elements())->set(0, *subject);
6331 return *result;
6332 }
6333
6334 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6335 int part_start = 0;
6336 for (int i = 0; i < part_count; i++) {
6337 HandleScope local_loop_handle;
6338 int part_end = indices.at(i);
6339 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006340 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006341 elements->set(i, *substring);
6342 part_start = part_end + pattern_length;
6343 }
6344
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006345 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006346 if (result->HasFastElements()) {
6347 StringSplitCache::Enter(isolate->heap(),
6348 isolate->heap()->string_split_cache(),
6349 *subject,
6350 *pattern,
6351 *elements);
6352 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006353 }
6354
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006355 return *result;
6356}
6357
6358
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006359// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006360// one-char strings in the cache. Gives up on the first char that is
6361// not in the cache and fills the remainder with smi zeros. Returns
6362// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006363static int CopyCachedAsciiCharsToArray(Heap* heap,
6364 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006365 FixedArray* elements,
6366 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006367 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006368 FixedArray* ascii_cache = heap->single_character_string_cache();
6369 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006370 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006371 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 for (i = 0; i < length; ++i) {
6373 Object* value = ascii_cache->get(chars[i]);
6374 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006375 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006376 }
6377 if (i < length) {
6378 ASSERT(Smi::FromInt(0) == 0);
6379 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6380 }
6381#ifdef DEBUG
6382 for (int j = 0; j < length; ++j) {
6383 Object* element = elements->get(j);
6384 ASSERT(element == Smi::FromInt(0) ||
6385 (element->IsString() && String::cast(element)->LooksValid()));
6386 }
6387#endif
6388 return i;
6389}
6390
6391
6392// Converts a String to JSArray.
6393// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006394RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006396 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006397 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006398 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006399
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006400 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006401 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006402
6403 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006404 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006405 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006406 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006407 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 { MaybeObject* maybe_obj =
6409 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006410 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006412 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006413 String::FlatContent content = s->GetFlatContent();
6414 if (content.IsAscii()) {
6415 Vector<const char> chars = content.ToAsciiVector();
6416 // Note, this will initialize all elements (not only the prefix)
6417 // to prevent GC from seeing partially initialized array.
6418 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6419 chars.start(),
6420 *elements,
6421 length);
6422 } else {
6423 MemsetPointer(elements->data_start(),
6424 isolate->heap()->undefined_value(),
6425 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006426 }
6427 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006429 }
6430 for (int i = position; i < length; ++i) {
6431 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6432 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006433 }
6434
6435#ifdef DEBUG
6436 for (int i = 0; i < length; ++i) {
6437 ASSERT(String::cast(elements->get(i))->length() == 1);
6438 }
6439#endif
6440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006442}
6443
6444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006445RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006446 NoHandleAllocation ha;
6447 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006448 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006449 return value->ToObject();
6450}
6451
6452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006453bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006454 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006456 return char_length == 0;
6457}
6458
6459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006460RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461 NoHandleAllocation ha;
6462 ASSERT(args.length() == 1);
6463
6464 Object* number = args[0];
6465 RUNTIME_ASSERT(number->IsNumber());
6466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468}
6469
6470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006471RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006472 NoHandleAllocation ha;
6473 ASSERT(args.length() == 1);
6474
6475 Object* number = args[0];
6476 RUNTIME_ASSERT(number->IsNumber());
6477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006479}
6480
6481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006482RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483 NoHandleAllocation ha;
6484 ASSERT(args.length() == 1);
6485
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006486 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006487
6488 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6489 if (number > 0 && number <= Smi::kMaxValue) {
6490 return Smi::FromInt(static_cast<int>(number));
6491 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 1);
6499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006500 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006501
6502 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6503 if (number > 0 && number <= Smi::kMaxValue) {
6504 return Smi::FromInt(static_cast<int>(number));
6505 }
6506
6507 double double_value = DoubleToInteger(number);
6508 // Map both -0 and +0 to +0.
6509 if (double_value == 0) double_value = 0;
6510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006512}
6513
6514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006515RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516 NoHandleAllocation ha;
6517 ASSERT(args.length() == 1);
6518
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006519 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521}
6522
6523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006524RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525 NoHandleAllocation ha;
6526 ASSERT(args.length() == 1);
6527
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006528 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006529
6530 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6531 if (number > 0 && number <= Smi::kMaxValue) {
6532 return Smi::FromInt(static_cast<int>(number));
6533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006534 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535}
6536
6537
ager@chromium.org870a0b62008-11-04 11:43:05 +00006538// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6539// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006540RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006541 NoHandleAllocation ha;
6542 ASSERT(args.length() == 1);
6543
6544 Object* obj = args[0];
6545 if (obj->IsSmi()) {
6546 return obj;
6547 }
6548 if (obj->IsHeapNumber()) {
6549 double value = HeapNumber::cast(obj)->value();
6550 int int_value = FastD2I(value);
6551 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6552 return Smi::FromInt(int_value);
6553 }
6554 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006555 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006556}
6557
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006559RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006560 NoHandleAllocation ha;
6561 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006562 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006563}
6564
6565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 2);
6569
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006570 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6571 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006572 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573}
6574
6575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006576RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577 NoHandleAllocation ha;
6578 ASSERT(args.length() == 2);
6579
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006580 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6581 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006582 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583}
6584
6585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006586RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 NoHandleAllocation ha;
6588 ASSERT(args.length() == 2);
6589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006590 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6591 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006592 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593}
6594
6595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006596RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597 NoHandleAllocation ha;
6598 ASSERT(args.length() == 1);
6599
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006600 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602}
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 0);
6608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006610}
6611
6612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006613RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614 NoHandleAllocation ha;
6615 ASSERT(args.length() == 2);
6616
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006617 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6618 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620}
6621
6622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006623RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624 NoHandleAllocation ha;
6625 ASSERT(args.length() == 2);
6626
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006627 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6628 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629
ager@chromium.org3811b432009-10-28 14:53:37 +00006630 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006631 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006639 CONVERT_ARG_CHECKED(String, str1, 0);
6640 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 isolate->counters()->string_add_runtime()->Increment();
6642 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
6644
6645
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006646template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647static inline void StringBuilderConcatHelper(String* special,
6648 sinkchar* sink,
6649 FixedArray* fixed_array,
6650 int array_length) {
6651 int position = 0;
6652 for (int i = 0; i < array_length; i++) {
6653 Object* element = fixed_array->get(i);
6654 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006655 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006656 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006657 int pos;
6658 int len;
6659 if (encoded_slice > 0) {
6660 // Position and length encoded in one smi.
6661 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6662 len = StringBuilderSubstringLength::decode(encoded_slice);
6663 } else {
6664 // Position and length encoded in two smis.
6665 Object* obj = fixed_array->get(++i);
6666 ASSERT(obj->IsSmi());
6667 pos = Smi::cast(obj)->value();
6668 len = -encoded_slice;
6669 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006670 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006671 sink + position,
6672 pos,
6673 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006674 position += len;
6675 } else {
6676 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006677 int element_length = string->length();
6678 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006679 position += element_length;
6680 }
6681 }
6682}
6683
6684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006685RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006687 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006688 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006689 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006690 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006691 return Failure::OutOfMemoryException();
6692 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006693 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006694 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006695
6696 // This assumption is used by the slice encoding in one or two smis.
6697 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6698
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006699 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006700 if (maybe_result->IsFailure()) return maybe_result;
6701
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006702 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 }
6706 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006707 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710
6711 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713 } else if (array_length == 1) {
6714 Object* first = fixed_array->get(0);
6715 if (first->IsString()) return first;
6716 }
6717
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006718 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719 int position = 0;
6720 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006721 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 Object* elt = fixed_array->get(i);
6723 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006724 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006725 int smi_value = Smi::cast(elt)->value();
6726 int pos;
6727 int len;
6728 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006729 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006730 pos = StringBuilderSubstringPosition::decode(smi_value);
6731 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006732 } else {
6733 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006734 len = -smi_value;
6735 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006736 i++;
6737 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006739 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006740 Object* next_smi = fixed_array->get(i);
6741 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006743 }
6744 pos = Smi::cast(next_smi)->value();
6745 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006749 ASSERT(pos >= 0);
6750 ASSERT(len >= 0);
6751 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006753 }
6754 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 } else if (elt->IsString()) {
6756 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006757 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006758 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006759 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006765 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006766 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006767 return Failure::OutOfMemoryException();
6768 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006769 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 }
6771
6772 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006775 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006776 { MaybeObject* maybe_object =
6777 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006778 if (!maybe_object->ToObject(&object)) return maybe_object;
6779 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006780 SeqAsciiString* answer = SeqAsciiString::cast(object);
6781 StringBuilderConcatHelper(special,
6782 answer->GetChars(),
6783 fixed_array,
6784 array_length);
6785 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787 { MaybeObject* maybe_object =
6788 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006789 if (!maybe_object->ToObject(&object)) return maybe_object;
6790 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006791 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6792 StringBuilderConcatHelper(special,
6793 answer->GetChars(),
6794 fixed_array,
6795 array_length);
6796 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798}
6799
6800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006801RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 NoHandleAllocation ha;
6803 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006804 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006805 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 return Failure::OutOfMemoryException();
6808 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006809 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006810 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006811
6812 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006814 }
6815 FixedArray* fixed_array = FixedArray::cast(array->elements());
6816 if (fixed_array->length() < array_length) {
6817 array_length = fixed_array->length();
6818 }
6819
6820 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006821 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006822 } else if (array_length == 1) {
6823 Object* first = fixed_array->get(0);
6824 if (first->IsString()) return first;
6825 }
6826
6827 int separator_length = separator->length();
6828 int max_nof_separators =
6829 (String::kMaxLength + separator_length - 1) / separator_length;
6830 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006832 return Failure::OutOfMemoryException();
6833 }
6834 int length = (array_length - 1) * separator_length;
6835 for (int i = 0; i < array_length; i++) {
6836 Object* element_obj = fixed_array->get(i);
6837 if (!element_obj->IsString()) {
6838 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006839 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006840 }
6841 String* element = String::cast(element_obj);
6842 int increment = element->length();
6843 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006845 return Failure::OutOfMemoryException();
6846 }
6847 length += increment;
6848 }
6849
6850 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006851 { MaybeObject* maybe_object =
6852 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006853 if (!maybe_object->ToObject(&object)) return maybe_object;
6854 }
6855 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6856
6857 uc16* sink = answer->GetChars();
6858#ifdef DEBUG
6859 uc16* end = sink + length;
6860#endif
6861
6862 String* first = String::cast(fixed_array->get(0));
6863 int first_length = first->length();
6864 String::WriteToFlat(first, sink, 0, first_length);
6865 sink += first_length;
6866
6867 for (int i = 1; i < array_length; i++) {
6868 ASSERT(sink + separator_length <= end);
6869 String::WriteToFlat(separator, sink, 0, separator_length);
6870 sink += separator_length;
6871
6872 String* element = String::cast(fixed_array->get(i));
6873 int element_length = element->length();
6874 ASSERT(sink + element_length <= end);
6875 String::WriteToFlat(element, sink, 0, element_length);
6876 sink += element_length;
6877 }
6878 ASSERT(sink == end);
6879
6880 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6881 return answer;
6882}
6883
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006884template <typename Char>
6885static void JoinSparseArrayWithSeparator(FixedArray* elements,
6886 int elements_length,
6887 uint32_t array_length,
6888 String* separator,
6889 Vector<Char> buffer) {
6890 int previous_separator_position = 0;
6891 int separator_length = separator->length();
6892 int cursor = 0;
6893 for (int i = 0; i < elements_length; i += 2) {
6894 int position = NumberToInt32(elements->get(i));
6895 String* string = String::cast(elements->get(i + 1));
6896 int string_length = string->length();
6897 if (string->length() > 0) {
6898 while (previous_separator_position < position) {
6899 String::WriteToFlat<Char>(separator, &buffer[cursor],
6900 0, separator_length);
6901 cursor += separator_length;
6902 previous_separator_position++;
6903 }
6904 String::WriteToFlat<Char>(string, &buffer[cursor],
6905 0, string_length);
6906 cursor += string->length();
6907 }
6908 }
6909 if (separator_length > 0) {
6910 // Array length must be representable as a signed 32-bit number,
6911 // otherwise the total string length would have been too large.
6912 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6913 int last_array_index = static_cast<int>(array_length - 1);
6914 while (previous_separator_position < last_array_index) {
6915 String::WriteToFlat<Char>(separator, &buffer[cursor],
6916 0, separator_length);
6917 cursor += separator_length;
6918 previous_separator_position++;
6919 }
6920 }
6921 ASSERT(cursor <= buffer.length());
6922}
6923
6924
6925RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6926 NoHandleAllocation ha;
6927 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006928 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006929 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6930 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006931 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006932 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006933 // elements_array is fast-mode JSarray of alternating positions
6934 // (increasing order) and strings.
6935 // array_length is length of original array (used to add separators);
6936 // separator is string to put between elements. Assumed to be non-empty.
6937
6938 // Find total length of join result.
6939 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006940 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006941 int max_string_length;
6942 if (is_ascii) {
6943 max_string_length = SeqAsciiString::kMaxLength;
6944 } else {
6945 max_string_length = SeqTwoByteString::kMaxLength;
6946 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006947 bool overflow = false;
6948 CONVERT_NUMBER_CHECKED(int, elements_length,
6949 Int32, elements_array->length());
6950 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6951 FixedArray* elements = FixedArray::cast(elements_array->elements());
6952 for (int i = 0; i < elements_length; i += 2) {
6953 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006954 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6955 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006956 int length = string->length();
6957 if (is_ascii && !string->IsAsciiRepresentation()) {
6958 is_ascii = false;
6959 max_string_length = SeqTwoByteString::kMaxLength;
6960 }
6961 if (length > max_string_length ||
6962 max_string_length - length < string_length) {
6963 overflow = true;
6964 break;
6965 }
6966 string_length += length;
6967 }
6968 int separator_length = separator->length();
6969 if (!overflow && separator_length > 0) {
6970 if (array_length <= 0x7fffffffu) {
6971 int separator_count = static_cast<int>(array_length) - 1;
6972 int remaining_length = max_string_length - string_length;
6973 if ((remaining_length / separator_length) >= separator_count) {
6974 string_length += separator_length * (array_length - 1);
6975 } else {
6976 // Not room for the separators within the maximal string length.
6977 overflow = true;
6978 }
6979 } else {
6980 // Nonempty separator and at least 2^31-1 separators necessary
6981 // means that the string is too large to create.
6982 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6983 overflow = true;
6984 }
6985 }
6986 if (overflow) {
6987 // Throw OutOfMemory exception for creating too large a string.
6988 V8::FatalProcessOutOfMemory("Array join result too large.");
6989 }
6990
6991 if (is_ascii) {
6992 MaybeObject* result_allocation =
6993 isolate->heap()->AllocateRawAsciiString(string_length);
6994 if (result_allocation->IsFailure()) return result_allocation;
6995 SeqAsciiString* result_string =
6996 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6997 JoinSparseArrayWithSeparator<char>(elements,
6998 elements_length,
6999 array_length,
7000 separator,
7001 Vector<char>(result_string->GetChars(),
7002 string_length));
7003 return result_string;
7004 } else {
7005 MaybeObject* result_allocation =
7006 isolate->heap()->AllocateRawTwoByteString(string_length);
7007 if (result_allocation->IsFailure()) return result_allocation;
7008 SeqTwoByteString* result_string =
7009 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7010 JoinSparseArrayWithSeparator<uc16>(elements,
7011 elements_length,
7012 array_length,
7013 separator,
7014 Vector<uc16>(result_string->GetChars(),
7015 string_length));
7016 return result_string;
7017 }
7018}
7019
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007021RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 NoHandleAllocation ha;
7023 ASSERT(args.length() == 2);
7024
7025 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7026 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007027 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028}
7029
7030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032 NoHandleAllocation ha;
7033 ASSERT(args.length() == 2);
7034
7035 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7036 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038}
7039
7040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042 NoHandleAllocation ha;
7043 ASSERT(args.length() == 2);
7044
7045 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7046 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007047 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048}
7049
7050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007051RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052 NoHandleAllocation ha;
7053 ASSERT(args.length() == 1);
7054
7055 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007056 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057}
7058
7059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007060RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 2);
7063
7064 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7065 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067}
7068
7069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087}
7088
7089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007090RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
7093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007094 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7095 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7097 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7098 if (x == y) return Smi::FromInt(EQUAL);
7099 Object* result;
7100 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7101 result = Smi::FromInt(EQUAL);
7102 } else {
7103 result = Smi::FromInt(NOT_EQUAL);
7104 }
7105 return result;
7106}
7107
7108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
7112
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007113 CONVERT_ARG_CHECKED(String, x, 0);
7114 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007115
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007116 bool not_equal = !x->Equals(y);
7117 // This is slightly convoluted because the value that signifies
7118 // equality is 0 and inequality is 1 so we have to negate the result
7119 // from String::Equals.
7120 ASSERT(not_equal == 0 || not_equal == 1);
7121 STATIC_CHECK(EQUAL == 0);
7122 STATIC_CHECK(NOT_EQUAL == 1);
7123 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124}
7125
7126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007127RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128 NoHandleAllocation ha;
7129 ASSERT(args.length() == 3);
7130
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007131 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7132 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 if (isnan(x) || isnan(y)) return args[2];
7134 if (x == y) return Smi::FromInt(EQUAL);
7135 if (isless(x, y)) return Smi::FromInt(LESS);
7136 return Smi::FromInt(GREATER);
7137}
7138
7139
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140// Compare two Smis as if they were converted to strings and then
7141// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007142RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007143 NoHandleAllocation ha;
7144 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007145 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7146 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147
7148 // If the integers are equal so are the string representations.
7149 if (x_value == y_value) return Smi::FromInt(EQUAL);
7150
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007151 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007153 if (x_value == 0 || y_value == 0)
7154 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007155
ager@chromium.org32912102009-01-16 10:38:43 +00007156 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007157 // smallest because the char code of '-' is less than the char code
7158 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007159
7160 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7161 // architectures using 32-bit Smis.
7162 uint32_t x_scaled = x_value;
7163 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007164 if (x_value < 0 || y_value < 0) {
7165 if (y_value >= 0) return Smi::FromInt(LESS);
7166 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007167 x_scaled = -x_value;
7168 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007169 }
7170
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007171 static const uint32_t kPowersOf10[] = {
7172 1, 10, 100, 1000, 10*1000, 100*1000,
7173 1000*1000, 10*1000*1000, 100*1000*1000,
7174 1000*1000*1000
7175 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007177 // If the integers have the same number of decimal digits they can be
7178 // compared directly as the numeric order is the same as the
7179 // lexicographic order. If one integer has fewer digits, it is scaled
7180 // by some power of 10 to have the same number of digits as the longer
7181 // integer. If the scaled integers are equal it means the shorter
7182 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007183
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007184 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7185 int x_log2 = IntegerLog2(x_scaled);
7186 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7187 x_log10 -= x_scaled < kPowersOf10[x_log10];
7188
7189 int y_log2 = IntegerLog2(y_scaled);
7190 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7191 y_log10 -= y_scaled < kPowersOf10[y_log10];
7192
7193 int tie = EQUAL;
7194
7195 if (x_log10 < y_log10) {
7196 // X has fewer digits. We would like to simply scale up X but that
7197 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7198 // be scaled up to 9_000_000_000. So we scale up by the next
7199 // smallest power and scale down Y to drop one digit. It is OK to
7200 // drop one digit from the longer integer since the final digit is
7201 // past the length of the shorter integer.
7202 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7203 y_scaled /= 10;
7204 tie = LESS;
7205 } else if (y_log10 < x_log10) {
7206 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7207 x_scaled /= 10;
7208 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007209 }
7210
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007211 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7212 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7213 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007214}
7215
7216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007217static Object* StringInputBufferCompare(RuntimeState* state,
7218 String* x,
7219 String* y) {
7220 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7221 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007222 bufx.Reset(x);
7223 bufy.Reset(y);
7224 while (bufx.has_more() && bufy.has_more()) {
7225 int d = bufx.GetNext() - bufy.GetNext();
7226 if (d < 0) return Smi::FromInt(LESS);
7227 else if (d > 0) return Smi::FromInt(GREATER);
7228 }
7229
7230 // x is (non-trivial) prefix of y:
7231 if (bufy.has_more()) return Smi::FromInt(LESS);
7232 // y is prefix of x:
7233 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7234}
7235
7236
7237static Object* FlatStringCompare(String* x, String* y) {
7238 ASSERT(x->IsFlat());
7239 ASSERT(y->IsFlat());
7240 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7241 int prefix_length = x->length();
7242 if (y->length() < prefix_length) {
7243 prefix_length = y->length();
7244 equal_prefix_result = Smi::FromInt(GREATER);
7245 } else if (y->length() > prefix_length) {
7246 equal_prefix_result = Smi::FromInt(LESS);
7247 }
7248 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007249 String::FlatContent x_content = x->GetFlatContent();
7250 String::FlatContent y_content = y->GetFlatContent();
7251 if (x_content.IsAscii()) {
7252 Vector<const char> x_chars = x_content.ToAsciiVector();
7253 if (y_content.IsAscii()) {
7254 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007255 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007256 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007257 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007258 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7259 }
7260 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007261 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7262 if (y_content.IsAscii()) {
7263 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007264 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7265 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007266 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007267 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7268 }
7269 }
7270 Object* result;
7271 if (r == 0) {
7272 result = equal_prefix_result;
7273 } else {
7274 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007276 ASSERT(result ==
7277 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007278 return result;
7279}
7280
7281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007282RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 NoHandleAllocation ha;
7284 ASSERT(args.length() == 2);
7285
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007286 CONVERT_ARG_CHECKED(String, x, 0);
7287 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007291 // A few fast case tests before we flatten.
7292 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007293 if (y->length() == 0) {
7294 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007296 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297 return Smi::FromInt(LESS);
7298 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007300 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007301 if (d < 0) return Smi::FromInt(LESS);
7302 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303
lrn@chromium.org303ada72010-10-27 09:33:13 +00007304 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007306 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7307 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007308 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007309 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7310 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007312 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314}
7315
7316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007317RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 NoHandleAllocation ha;
7319 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007322 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324}
7325
7326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007327RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328 NoHandleAllocation ha;
7329 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007332 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334}
7335
7336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007337RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338 NoHandleAllocation ha;
7339 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007342 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344}
7345
7346
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347static const double kPiDividedBy4 = 0.78539816339744830962;
7348
7349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007350RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351 NoHandleAllocation ha;
7352 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007355 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7356 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357 double result;
7358 if (isinf(x) && isinf(y)) {
7359 // Make sure that the result in case of two infinite arguments
7360 // is a multiple of Pi / 4. The sign of the result is determined
7361 // by the first argument (x) and the sign of the second argument
7362 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363 int multiplier = (x < 0) ? -1 : 1;
7364 if (y < 0) multiplier *= 3;
7365 result = multiplier * kPiDividedBy4;
7366 } else {
7367 result = atan2(x, y);
7368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 NoHandleAllocation ha;
7385 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007388 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390}
7391
7392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 NoHandleAllocation ha;
7395 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007398 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400}
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410}
7411
7412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007413RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 NoHandleAllocation ha;
7415 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007416 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007418 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007422// Slow version of Math.pow. We check for fast paths for special cases.
7423// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 NoHandleAllocation ha;
7426 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007429 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007430
7431 // If the second argument is a smi, it is much faster to call the
7432 // custom powi() function than the generic pow().
7433 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007434 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007435 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007436 }
7437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007438 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007439 int y_int = static_cast<int>(y);
7440 double result;
7441 if (y == y_int) {
7442 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7443 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007444 result = (isinf(x)) ? V8_INFINITY
7445 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007446 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007447 result = (isinf(x)) ? 0
7448 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007449 } else {
7450 result = power_double_double(x, y);
7451 }
7452 if (isnan(result)) return isolate->heap()->nan_value();
7453 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454}
7455
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007456// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007457// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007458RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007459 NoHandleAllocation ha;
7460 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007461 isolate->counters()->math_pow()->Increment();
7462
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007463 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7464 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007465 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007466 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007467 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007468 double result = power_double_double(x, y);
7469 if (isnan(result)) return isolate->heap()->nan_value();
7470 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007471 }
7472}
7473
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007475RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476 NoHandleAllocation ha;
7477 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007480 if (!args[0]->IsHeapNumber()) {
7481 // Must be smi. Return the argument unchanged for all the other types
7482 // to make fuzz-natives test happy.
7483 return args[0];
7484 }
7485
7486 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7487
7488 double value = number->value();
7489 int exponent = number->get_exponent();
7490 int sign = number->get_sign();
7491
danno@chromium.org160a7b02011-04-18 15:51:38 +00007492 if (exponent < -1) {
7493 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7494 if (sign) return isolate->heap()->minus_zero_value();
7495 return Smi::FromInt(0);
7496 }
7497
7498 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7499 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007500 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007501 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007502 return Smi::FromInt(static_cast<int>(value + 0.5));
7503 }
7504
7505 // If the magnitude is big enough, there's no place for fraction part. If we
7506 // try to add 0.5 to this number, 1.0 will be added instead.
7507 if (exponent >= 52) {
7508 return number;
7509 }
7510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007512
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007513 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515}
7516
7517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007518RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519 NoHandleAllocation ha;
7520 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007523 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525}
7526
7527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007528RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007529 NoHandleAllocation ha;
7530 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007533 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007534 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007535}
7536
7537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007538RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539 NoHandleAllocation ha;
7540 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007541 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007543 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545}
7546
7547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007548RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007549 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007550 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007551
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007552 CONVERT_SMI_ARG_CHECKED(year, 0);
7553 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007554
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007555 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007556}
7557
7558
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007559RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7560 HandleScope scope(isolate);
7561 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007562
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007563 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7564 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7565 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007567 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007568
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007569 Object* value = NULL;
7570 bool is_value_nan = false;
7571 if (isnan(time)) {
7572 value = isolate->heap()->nan_value();
7573 is_value_nan = true;
7574 } else if (!is_utc &&
7575 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7576 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7577 value = isolate->heap()->nan_value();
7578 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007579 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007580 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7581 if (time < -DateCache::kMaxTimeInMs ||
7582 time > DateCache::kMaxTimeInMs) {
7583 value = isolate->heap()->nan_value();
7584 is_value_nan = true;
7585 } else {
7586 MaybeObject* maybe_result =
7587 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7588 if (!maybe_result->ToObject(&value)) return maybe_result;
7589 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007590 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007591 date->SetValue(value, is_value_nan);
7592 return *date;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007593}
7594
7595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007596RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007597 HandleScope scope(isolate);
7598 ASSERT(args.length() == 3);
7599
7600 Handle<JSFunction> callee = args.at<JSFunction>(0);
7601 Object** parameters = reinterpret_cast<Object**>(args[1]);
7602 const int argument_count = Smi::cast(args[2])->value();
7603
7604 Handle<JSObject> result =
7605 isolate->factory()->NewArgumentsObject(callee, argument_count);
7606 // Allocate the elements if needed.
7607 int parameter_count = callee->shared()->formal_parameter_count();
7608 if (argument_count > 0) {
7609 if (parameter_count > 0) {
7610 int mapped_count = Min(argument_count, parameter_count);
7611 Handle<FixedArray> parameter_map =
7612 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7613 parameter_map->set_map(
7614 isolate->heap()->non_strict_arguments_elements_map());
7615
7616 Handle<Map> old_map(result->map());
7617 Handle<Map> new_map =
7618 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007619 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007620
7621 result->set_map(*new_map);
7622 result->set_elements(*parameter_map);
7623
7624 // Store the context and the arguments array at the beginning of the
7625 // parameter map.
7626 Handle<Context> context(isolate->context());
7627 Handle<FixedArray> arguments =
7628 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7629 parameter_map->set(0, *context);
7630 parameter_map->set(1, *arguments);
7631
7632 // Loop over the actual parameters backwards.
7633 int index = argument_count - 1;
7634 while (index >= mapped_count) {
7635 // These go directly in the arguments array and have no
7636 // corresponding slot in the parameter map.
7637 arguments->set(index, *(parameters - index - 1));
7638 --index;
7639 }
7640
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007641 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007642 while (index >= 0) {
7643 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007644 Handle<String> name(scope_info->ParameterName(index));
7645 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007646 bool duplicate = false;
7647 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007648 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007649 duplicate = true;
7650 break;
7651 }
7652 }
7653
7654 if (duplicate) {
7655 // This goes directly in the arguments array with a hole in the
7656 // parameter map.
7657 arguments->set(index, *(parameters - index - 1));
7658 parameter_map->set_the_hole(index + 2);
7659 } else {
7660 // The context index goes in the parameter map with a hole in the
7661 // arguments array.
7662 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007663 for (int j = 0; j < context_local_count; ++j) {
7664 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007665 context_index = j;
7666 break;
7667 }
7668 }
7669 ASSERT(context_index >= 0);
7670 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007671 parameter_map->set(index + 2, Smi::FromInt(
7672 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007673 }
7674
7675 --index;
7676 }
7677 } else {
7678 // If there is no aliasing, the arguments object elements are not
7679 // special in any way.
7680 Handle<FixedArray> elements =
7681 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7682 result->set_elements(*elements);
7683 for (int i = 0; i < argument_count; ++i) {
7684 elements->set(i, *(parameters - i - 1));
7685 }
7686 }
7687 }
7688 return *result;
7689}
7690
7691
7692RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007693 NoHandleAllocation ha;
7694 ASSERT(args.length() == 3);
7695
7696 JSFunction* callee = JSFunction::cast(args[0]);
7697 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007698 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007699
lrn@chromium.org303ada72010-10-27 09:33:13 +00007700 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007701 { MaybeObject* maybe_result =
7702 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007703 if (!maybe_result->ToObject(&result)) return maybe_result;
7704 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007705 // Allocate the elements if needed.
7706 if (length > 0) {
7707 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007708 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007709 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007710 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7711 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007712
7713 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007714 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007715 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007716 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007717
7718 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007719 for (int i = 0; i < length; i++) {
7720 array->set(i, *--parameters, mode);
7721 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007722 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007723 }
7724 return result;
7725}
7726
7727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007728RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007729 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007730 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007731 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7732 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7733 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007734
whesse@chromium.org7b260152011-06-20 15:33:18 +00007735 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007736 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007737 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007738 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7740 context,
7741 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742 return *result;
7743}
7744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007745
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007746// Find the arguments of the JavaScript function invocation that called
7747// into C++ code. Collect these in a newly allocated array of handles (possibly
7748// prefixed by a number of empty handles).
7749static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7750 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007751 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007752 // Find frame containing arguments passed to the caller.
7753 JavaScriptFrameIterator it;
7754 JavaScriptFrame* frame = it.frame();
7755 List<JSFunction*> functions(2);
7756 frame->GetFunctions(&functions);
7757 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007758 int inlined_jsframe_index = functions.length() - 1;
7759 JSFunction* inlined_function = functions[inlined_jsframe_index];
7760 Vector<SlotRef> args_slots =
7761 SlotRef::ComputeSlotMappingForArguments(
7762 frame,
7763 inlined_jsframe_index,
7764 inlined_function->shared()->formal_parameter_count());
7765
7766 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007767
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007768 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007769 SmartArrayPointer<Handle<Object> > param_data(
7770 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771 for (int i = 0; i < args_count; i++) {
7772 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007773 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007774 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007775
7776 args_slots.Dispose();
7777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007778 return param_data;
7779 } else {
7780 it.AdvanceToArgumentsFrame();
7781 frame = it.frame();
7782 int args_count = frame->ComputeParametersCount();
7783
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007784 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007785 SmartArrayPointer<Handle<Object> > param_data(
7786 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007787 for (int i = 0; i < args_count; i++) {
7788 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007789 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007790 }
7791 return param_data;
7792 }
7793}
7794
7795
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007796RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7797 HandleScope scope(isolate);
7798 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007799 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007800 RUNTIME_ASSERT(args[3]->IsNumber());
7801 Handle<Object> bindee = args.at<Object>(1);
7802
7803 // TODO(lrn): Create bound function in C++ code from premade shared info.
7804 bound_function->shared()->set_bound(true);
7805 // Get all arguments of calling function (Function.prototype.bind).
7806 int argc = 0;
7807 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7808 // Don't count the this-arg.
7809 if (argc > 0) {
7810 ASSERT(*arguments[0] == args[2]);
7811 argc--;
7812 } else {
7813 ASSERT(args[2]->IsUndefined());
7814 }
7815 // Initialize array of bindings (function, this, and any existing arguments
7816 // if the function was already bound).
7817 Handle<FixedArray> new_bindings;
7818 int i;
7819 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7820 Handle<FixedArray> old_bindings(
7821 JSFunction::cast(*bindee)->function_bindings());
7822 new_bindings =
7823 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7824 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7825 i = 0;
7826 for (int n = old_bindings->length(); i < n; i++) {
7827 new_bindings->set(i, old_bindings->get(i));
7828 }
7829 } else {
7830 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7831 new_bindings = isolate->factory()->NewFixedArray(array_size);
7832 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7833 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7834 i = 2;
7835 }
7836 // Copy arguments, skipping the first which is "this_arg".
7837 for (int j = 0; j < argc; j++, i++) {
7838 new_bindings->set(i, *arguments[j + 1]);
7839 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007840 new_bindings->set_map_no_write_barrier(
7841 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007842 bound_function->set_function_bindings(*new_bindings);
7843
7844 // Update length.
7845 Handle<String> length_symbol = isolate->factory()->length_symbol();
7846 Handle<Object> new_length(args.at<Object>(3));
7847 PropertyAttributes attr =
7848 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7849 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7850 return *bound_function;
7851}
7852
7853
7854RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7855 HandleScope handles(isolate);
7856 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007857 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007858 if (callable->IsJSFunction()) {
7859 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7860 if (function->shared()->bound()) {
7861 Handle<FixedArray> bindings(function->function_bindings());
7862 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7863 return *isolate->factory()->NewJSArrayWithElements(bindings);
7864 }
7865 }
7866 return isolate->heap()->undefined_value();
7867}
7868
7869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007870RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007872 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007873 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007874 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007875 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007876
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007877 // The argument is a bound function. Extract its bound arguments
7878 // and callable.
7879 Handle<FixedArray> bound_args =
7880 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7881 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7882 Handle<Object> bound_function(
7883 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7884 ASSERT(!bound_function->IsJSFunction() ||
7885 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007887 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007888 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007889 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007890 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007891 param_data[i] = Handle<Object>(bound_args->get(
7892 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007893 }
7894
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007895 if (!bound_function->IsJSFunction()) {
7896 bool exception_thrown;
7897 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7898 &exception_thrown);
7899 if (exception_thrown) return Failure::Exception();
7900 }
7901 ASSERT(bound_function->IsJSFunction());
7902
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007903 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007904 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007905 Execution::New(Handle<JSFunction>::cast(bound_function),
7906 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007907 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007908 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007909 }
7910 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007911 return *result;
7912}
7913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007915static void TrySettingInlineConstructStub(Isolate* isolate,
7916 Handle<JSFunction> function) {
7917 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007918 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007919 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007920 }
7921 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007922 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007923 Handle<Code> code = compiler.CompileConstructStub(function);
7924 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007925 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007926}
7927
7928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007929RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007930 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007931 ASSERT(args.length() == 1);
7932
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007933 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007935 // If the constructor isn't a proper function we throw a type error.
7936 if (!constructor->IsJSFunction()) {
7937 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7938 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007939 isolate->factory()->NewTypeError("not_constructor", arguments);
7940 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007941 }
7942
7943 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007944
7945 // If function should not have prototype, construction is not allowed. In this
7946 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007947 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007948 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7949 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007950 isolate->factory()->NewTypeError("not_constructor", arguments);
7951 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007952 }
7953
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007954#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007955 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007956 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007957 if (debug->StepInActive()) {
7958 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007959 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007960#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007962 if (function->has_initial_map()) {
7963 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007964 // The 'Function' function ignores the receiver object when
7965 // called using 'new' and creates a new JSFunction object that
7966 // is returned. The receiver object is only used for error
7967 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007968 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007969 // allocate JSFunctions since it does not properly initialize
7970 // the shared part of the function. Since the receiver is
7971 // ignored anyway, we use the global object as the receiver
7972 // instead of a new JSFunction object. This way, errors are
7973 // reported the same way whether or not 'Function' is called
7974 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007975 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007977 }
7978
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007979 // The function should be compiled for the optimization hints to be
7980 // available. We cannot use EnsureCompiled because that forces a
7981 // compilation through the shared function info which makes it
7982 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007983 if (!function->is_compiled()) {
7984 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7985 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007986
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007987 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007988 if (!function->has_initial_map() &&
7989 shared->IsInobjectSlackTrackingInProgress()) {
7990 // The tracking is already in progress for another function. We can only
7991 // track one initial_map at a time, so we force the completion before the
7992 // function is called as a constructor for the first time.
7993 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007994 }
7995
7996 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7998 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007999 // Delay setting the stub if inobject slack tracking is in progress.
8000 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008001 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008002 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008004 isolate->counters()->constructed_objects()->Increment();
8005 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008006
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008007 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008}
8009
8010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008011RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008013 ASSERT(args.length() == 1);
8014
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008015 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008016 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008019 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008020}
8021
8022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008023RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 ASSERT(args.length() == 1);
8026
8027 Handle<JSFunction> function = args.at<JSFunction>(0);
8028#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008029 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032 PrintF("]\n");
8033 }
8034#endif
8035
lrn@chromium.org34e60782011-09-15 07:25:40 +00008036 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008038 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039 return Failure::Exception();
8040 }
8041
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008042 // All done. Return the compiled code.
8043 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008044 return function->code();
8045}
8046
8047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008048RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008050 ASSERT(args.length() == 1);
8051 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008052
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008053 function->shared()->set_profiler_ticks(0);
8054
lrn@chromium.org34e60782011-09-15 07:25:40 +00008055 // If the function is not compiled ignore the lazy
8056 // recompilation. This can happen if the debugger is activated and
8057 // the function is returned to the not compiled state.
8058 if (!function->shared()->is_compiled()) {
8059 function->ReplaceCode(function->shared()->code());
8060 return function->code();
8061 }
8062
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008063 // If the function is not optimizable or debugger is active continue using the
8064 // code from the full compiler.
8065 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008066 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008067 if (FLAG_trace_opt) {
8068 PrintF("[failed to optimize ");
8069 function->PrintName();
8070 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8071 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008072 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008073 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008074 function->ReplaceCode(function->shared()->code());
8075 return function->code();
8076 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008077 if (JSFunction::CompileOptimized(function,
8078 AstNode::kNoNumber,
8079 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008080 return function->code();
8081 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008082 if (FLAG_trace_opt) {
8083 PrintF("[failed to optimize ");
8084 function->PrintName();
8085 PrintF(": optimized compilation failed]\n");
8086 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008087 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008088 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008089}
8090
8091
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008092class ActivationsFinder : public ThreadVisitor {
8093 public:
8094 explicit ActivationsFinder(JSFunction* function)
8095 : function_(function), has_activations_(false) {}
8096
8097 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8098 if (has_activations_) return;
8099
8100 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8101 JavaScriptFrame* frame = it.frame();
8102 if (frame->is_optimized() && frame->function() == function_) {
8103 has_activations_ = true;
8104 return;
8105 }
8106 }
8107 }
8108
8109 bool has_activations() { return has_activations_; }
8110
8111 private:
8112 JSFunction* function_;
8113 bool has_activations_;
8114};
8115
8116
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008117static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8118 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008119 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008120 Handle<Object> arguments;
8121 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008122 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008123 if (arguments.is_null()) {
8124 // FunctionGetArguments can't throw an exception, so cast away the
8125 // doubt with an assert.
8126 arguments = Handle<Object>(
8127 Accessors::FunctionGetArguments(*function,
8128 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008129 ASSERT(*arguments != isolate->heap()->null_value());
8130 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008131 }
8132 frame->SetExpression(i, *arguments);
8133 }
8134 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008135}
8136
8137
8138RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8139 HandleScope scope(isolate);
8140 ASSERT(args.length() == 1);
8141 RUNTIME_ASSERT(args[0]->IsSmi());
8142 Deoptimizer::BailoutType type =
8143 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8144 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8145 ASSERT(isolate->heap()->IsAllocationAllowed());
8146 int jsframes = deoptimizer->jsframe_count();
8147
8148 deoptimizer->MaterializeHeapNumbers();
8149 delete deoptimizer;
8150
8151 JavaScriptFrameIterator it(isolate);
8152 for (int i = 0; i < jsframes - 1; i++) {
8153 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8154 it.Advance();
8155 }
8156
8157 JavaScriptFrame* frame = it.frame();
8158 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8159 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8160 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008161
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008162 if (type == Deoptimizer::EAGER) {
8163 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008164 }
8165
8166 // Avoid doing too much work when running with --always-opt and keep
8167 // the optimized code around.
8168 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008169 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008170 }
8171
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008172 // Find other optimized activations of the function.
8173 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008174 while (!it.done()) {
8175 JavaScriptFrame* frame = it.frame();
8176 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008177 has_other_activations = true;
8178 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 }
8180 it.Advance();
8181 }
8182
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008183 if (!has_other_activations) {
8184 ActivationsFinder activations_finder(*function);
8185 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8186 has_other_activations = activations_finder.has_activations();
8187 }
8188
8189 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008190 if (FLAG_trace_deopt) {
8191 PrintF("[removing optimized code for: ");
8192 function->PrintName();
8193 PrintF("]\n");
8194 }
8195 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008196 } else {
8197 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008198 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008200}
8201
8202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008203RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008205 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008207}
8208
8209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008210RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008211 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008212 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008213 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008214 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008215
8216 Deoptimizer::DeoptimizeFunction(*function);
8217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008219}
8220
8221
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008222RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8223#if defined(USE_SIMULATOR)
8224 return isolate->heap()->true_value();
8225#else
8226 return isolate->heap()->false_value();
8227#endif
8228}
8229
8230
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008231RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8232 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008233 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008234 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008235
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008236 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8237 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008238
8239 Code* unoptimized = function->shared()->code();
8240 if (args.length() == 2 &&
8241 unoptimized->kind() == Code::FUNCTION) {
8242 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8243 CHECK(type->IsEqualTo(CStrVector("osr")));
8244 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8245 unoptimized->set_allow_osr_at_loop_nesting_level(
8246 Code::kMaxLoopNestingMarker);
8247 }
8248
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008249 return isolate->heap()->undefined_value();
8250}
8251
8252
lrn@chromium.org1c092762011-05-09 09:42:16 +00008253RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8254 HandleScope scope(isolate);
8255 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008256 // The least significant bit (after untagging) indicates whether the
8257 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008258 if (!V8::UseCrankshaft()) {
8259 return Smi::FromInt(4); // 4 == "never".
8260 }
8261 if (FLAG_always_opt) {
8262 return Smi::FromInt(3); // 3 == "always".
8263 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008264 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008265 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8266 : Smi::FromInt(2); // 2 == "no".
8267}
8268
8269
8270RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8271 HandleScope scope(isolate);
8272 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008273 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008274 return Smi::FromInt(function->shared()->opt_count());
8275}
8276
8277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008278RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008279 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008280 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008281 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008282
8283 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008284 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008285
8286 // We have hit a back edge in an unoptimized frame for a function that was
8287 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008288 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008289 // Keep track of whether we've succeeded in optimizing.
8290 bool succeeded = unoptimized->optimizable();
8291 if (succeeded) {
8292 // If we are trying to do OSR when there are already optimized
8293 // activations of the function, it means (a) the function is directly or
8294 // indirectly recursive and (b) an optimized invocation has been
8295 // deoptimized so that we are currently in an unoptimized activation.
8296 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008297 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008298 while (succeeded && !it.done()) {
8299 JavaScriptFrame* frame = it.frame();
8300 succeeded = !frame->is_optimized() || frame->function() != *function;
8301 it.Advance();
8302 }
8303 }
8304
8305 int ast_id = AstNode::kNoNumber;
8306 if (succeeded) {
8307 // The top JS function is this one, the PC is somewhere in the
8308 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008309 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008310 JavaScriptFrame* frame = it.frame();
8311 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008312 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008313 ASSERT(unoptimized->contains(frame->pc()));
8314
8315 // Use linear search of the unoptimized code's stack check table to find
8316 // the AST id matching the PC.
8317 Address start = unoptimized->instruction_start();
8318 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008319 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008320 uint32_t table_length = Memory::uint32_at(table_cursor);
8321 table_cursor += kIntSize;
8322 for (unsigned i = 0; i < table_length; ++i) {
8323 // Table entries are (AST id, pc offset) pairs.
8324 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8325 if (pc_offset == target_pc_offset) {
8326 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8327 break;
8328 }
8329 table_cursor += 2 * kIntSize;
8330 }
8331 ASSERT(ast_id != AstNode::kNoNumber);
8332 if (FLAG_trace_osr) {
8333 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8334 function->PrintName();
8335 PrintF("]\n");
8336 }
8337
8338 // Try to compile the optimized code. A true return value from
8339 // CompileOptimized means that compilation succeeded, not necessarily
8340 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008341 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008342 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008343 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8344 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008345 if (data->OsrPcOffset()->value() >= 0) {
8346 if (FLAG_trace_osr) {
8347 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008349 }
8350 ASSERT(data->OsrAstId()->value() == ast_id);
8351 } else {
8352 // We may never generate the desired OSR entry if we emit an
8353 // early deoptimize.
8354 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008355 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008356 } else {
8357 succeeded = false;
8358 }
8359 }
8360
8361 // Revert to the original stack checks in the original unoptimized code.
8362 if (FLAG_trace_osr) {
8363 PrintF("[restoring original stack checks in ");
8364 function->PrintName();
8365 PrintF("]\n");
8366 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008367 Handle<Code> check_code;
8368#ifdef V8_TARGET_ARCH_IA32
8369 if (FLAG_count_based_interrupts) {
8370 InterruptStub interrupt_stub;
8371 check_code = interrupt_stub.GetCode();
8372 } else // NOLINT
8373#endif
8374 { // NOLINT
8375 StackCheckStub check_stub;
8376 check_code = check_stub.GetCode();
8377 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008378 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008379 Deoptimizer::RevertStackCheckCode(*unoptimized,
8380 *check_code,
8381 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008382
8383 // Allow OSR only at nesting level zero again.
8384 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8385
8386 // If the optimization attempt succeeded, return the AST id tagged as a
8387 // smi. This tells the builtin that we need to translate the unoptimized
8388 // frame to an optimized one.
8389 if (succeeded) {
8390 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8391 return Smi::FromInt(ast_id);
8392 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008393 if (function->IsMarkedForLazyRecompilation()) {
8394 function->ReplaceCode(function->shared()->code());
8395 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008396 return Smi::FromInt(-1);
8397 }
8398}
8399
8400
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008401RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8402 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8403 return isolate->heap()->undefined_value();
8404}
8405
8406
danno@chromium.orgc612e022011-11-10 11:38:15 +00008407RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8408 HandleScope scope(isolate);
8409 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008410 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008411 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8412 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008413
8414 // If there are too many arguments, allocate argv via malloc.
8415 const int argv_small_size = 10;
8416 Handle<Object> argv_small_buffer[argv_small_size];
8417 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8418 Handle<Object>* argv = argv_small_buffer;
8419 if (argc > argv_small_size) {
8420 argv = new Handle<Object>[argc];
8421 if (argv == NULL) return isolate->StackOverflow();
8422 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8423 }
8424
8425 for (int i = 0; i < argc; ++i) {
8426 MaybeObject* maybe = args[1 + i];
8427 Object* object;
8428 if (!maybe->To<Object>(&object)) return maybe;
8429 argv[i] = Handle<Object>(object);
8430 }
8431
8432 bool threw;
8433 Handle<JSReceiver> hfun(fun);
8434 Handle<Object> hreceiver(receiver);
8435 Handle<Object> result =
8436 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8437
8438 if (threw) return Failure::Exception();
8439 return *result;
8440}
8441
8442
lrn@chromium.org34e60782011-09-15 07:25:40 +00008443RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8444 HandleScope scope(isolate);
8445 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008446 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008447 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008448 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008449 CONVERT_SMI_ARG_CHECKED(offset, 3);
8450 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008451 ASSERT(offset >= 0);
8452 ASSERT(argc >= 0);
8453
8454 // If there are too many arguments, allocate argv via malloc.
8455 const int argv_small_size = 10;
8456 Handle<Object> argv_small_buffer[argv_small_size];
8457 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8458 Handle<Object>* argv = argv_small_buffer;
8459 if (argc > argv_small_size) {
8460 argv = new Handle<Object>[argc];
8461 if (argv == NULL) return isolate->StackOverflow();
8462 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8463 }
8464
8465 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008466 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008467 }
8468
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008469 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008470 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008471 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008472
8473 if (threw) return Failure::Exception();
8474 return *result;
8475}
8476
8477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008478RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008479 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008480 ASSERT(args.length() == 1);
8481 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8482 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8483}
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008488 ASSERT(args.length() == 1);
8489 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8490 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8491}
8492
8493
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008494RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008495 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008496 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008497
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008498 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008499 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008500 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008501 { MaybeObject* maybe_result =
8502 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008503 if (!maybe_result->ToObject(&result)) return maybe_result;
8504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008505
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008506 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008507
kasper.lund7276f142008-07-30 08:49:36 +00008508 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509}
8510
lrn@chromium.org303ada72010-10-27 09:33:13 +00008511
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008512RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8513 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008514 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008515 JSObject* extension_object;
8516 if (args[0]->IsJSObject()) {
8517 extension_object = JSObject::cast(args[0]);
8518 } else {
8519 // Convert the object to a proper JavaScript object.
8520 MaybeObject* maybe_js_object = args[0]->ToObject();
8521 if (!maybe_js_object->To(&extension_object)) {
8522 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8523 HandleScope scope(isolate);
8524 Handle<Object> handle = args.at<Object>(0);
8525 Handle<Object> result =
8526 isolate->factory()->NewTypeError("with_expression",
8527 HandleVector(&handle, 1));
8528 return isolate->Throw(*result);
8529 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008530 return maybe_js_object;
8531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 }
8533 }
8534
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008535 JSFunction* function;
8536 if (args[1]->IsSmi()) {
8537 // A smi sentinel indicates a context nested inside global code rather
8538 // than some function. There is a canonical empty function that can be
8539 // gotten from the global context.
8540 function = isolate->context()->global_context()->closure();
8541 } else {
8542 function = JSFunction::cast(args[1]);
8543 }
8544
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008545 Context* context;
8546 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008547 isolate->heap()->AllocateWithContext(function,
8548 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008549 extension_object);
8550 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008551 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008552 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008553}
8554
8555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008556RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008557 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008558 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008559 String* name = String::cast(args[0]);
8560 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008561 JSFunction* function;
8562 if (args[2]->IsSmi()) {
8563 // A smi sentinel indicates a context nested inside global code rather
8564 // than some function. There is a canonical empty function that can be
8565 // gotten from the global context.
8566 function = isolate->context()->global_context()->closure();
8567 } else {
8568 function = JSFunction::cast(args[2]);
8569 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008570 Context* context;
8571 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008572 isolate->heap()->AllocateCatchContext(function,
8573 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008574 name,
8575 thrown_object);
8576 if (!maybe_context->To(&context)) return maybe_context;
8577 isolate->set_context(context);
8578 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008579}
8580
8581
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8583 NoHandleAllocation ha;
8584 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008585 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008586 JSFunction* function;
8587 if (args[1]->IsSmi()) {
8588 // A smi sentinel indicates a context nested inside global code rather
8589 // than some function. There is a canonical empty function that can be
8590 // gotten from the global context.
8591 function = isolate->context()->global_context()->closure();
8592 } else {
8593 function = JSFunction::cast(args[1]);
8594 }
8595 Context* context;
8596 MaybeObject* maybe_context =
8597 isolate->heap()->AllocateBlockContext(function,
8598 isolate->context(),
8599 scope_info);
8600 if (!maybe_context->To(&context)) return maybe_context;
8601 isolate->set_context(context);
8602 return context;
8603}
8604
8605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008606RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008608 ASSERT(args.length() == 2);
8609
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008610 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8611 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612
8613 int index;
8614 PropertyAttributes attributes;
8615 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008616 BindingFlags binding_flags;
8617 Handle<Object> holder = context->Lookup(name,
8618 flags,
8619 &index,
8620 &attributes,
8621 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008623 // If the slot was not found the result is true.
8624 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008625 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008626 }
8627
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008628 // If the slot was found in a context, it should be DONT_DELETE.
8629 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008630 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008631 }
8632
8633 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008634 // the global object, or the subject of a with. Try to delete it
8635 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008636 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008637 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008638}
8639
8640
ager@chromium.orga1645e22009-09-09 19:27:10 +00008641// A mechanism to return a pair of Object pointers in registers (if possible).
8642// How this is achieved is calling convention-dependent.
8643// All currently supported x86 compiles uses calling conventions that are cdecl
8644// variants where a 64-bit value is returned in two 32-bit registers
8645// (edx:eax on ia32, r1:r0 on ARM).
8646// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8647// In Win64 calling convention, a struct of two pointers is returned in memory,
8648// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008649#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008650struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008651 MaybeObject* x;
8652 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008653};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008654
lrn@chromium.org303ada72010-10-27 09:33:13 +00008655static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008656 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008657 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8658 // In Win64 they are assigned to a hidden first argument.
8659 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008660}
8661#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008662typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008663static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008665 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008667#endif
8668
8669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008670static inline MaybeObject* Unhole(Heap* heap,
8671 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008672 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008673 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8674 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008675 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676}
8677
8678
danno@chromium.org40cb8782011-05-25 07:58:50 +00008679static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8680 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008681 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008682 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008683 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008684 JSFunction* context_extension_function =
8685 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008686 // If the holder isn't a context extension object, we just return it
8687 // as the receiver. This allows arguments objects to be used as
8688 // receivers, but only if they are put in the context scope chain
8689 // explicitly via a with-statement.
8690 Object* constructor = holder->map()->constructor();
8691 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008692 // Fall back to using the global object as the implicit receiver if
8693 // the property turns out to be a local variable allocated in a
8694 // context extension object - introduced via eval. Implicit global
8695 // receivers are indicated with the hole value.
8696 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008697}
8698
8699
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008700static ObjectPair LoadContextSlotHelper(Arguments args,
8701 Isolate* isolate,
8702 bool throw_error) {
8703 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008704 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008705
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008706 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008707 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008710 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711
8712 int index;
8713 PropertyAttributes attributes;
8714 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008715 BindingFlags binding_flags;
8716 Handle<Object> holder = context->Lookup(name,
8717 flags,
8718 &index,
8719 &attributes,
8720 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008721
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008722 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008723 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008724 ASSERT(holder->IsContext());
8725 // If the "property" we were looking for is a local variable, the
8726 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008727 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008728 // Use the hole as the receiver to signal that the receiver is implicit
8729 // and that the global receiver should be used (as distinguished from an
8730 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008731 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008732 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008733 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008734 switch (binding_flags) {
8735 case MUTABLE_CHECK_INITIALIZED:
8736 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8737 if (value->IsTheHole()) {
8738 Handle<Object> reference_error =
8739 isolate->factory()->NewReferenceError("not_defined",
8740 HandleVector(&name, 1));
8741 return MakePair(isolate->Throw(*reference_error), NULL);
8742 }
8743 // FALLTHROUGH
8744 case MUTABLE_IS_INITIALIZED:
8745 case IMMUTABLE_IS_INITIALIZED:
8746 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8747 ASSERT(!value->IsTheHole());
8748 return MakePair(value, *receiver);
8749 case IMMUTABLE_CHECK_INITIALIZED:
8750 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8751 case MISSING_BINDING:
8752 UNREACHABLE();
8753 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008754 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008755 }
8756
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008757 // Otherwise, if the slot was found the holder is a context extension
8758 // object, subject of a with, or a global object. We read the named
8759 // property from it.
8760 if (!holder.is_null()) {
8761 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8762 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008763 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008764 Handle<Object> receiver_handle(object->IsGlobalObject()
8765 ? GlobalObject::cast(*object)->global_receiver()
8766 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008767
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008768 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008769 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008770 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008771 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772 }
8773
8774 if (throw_error) {
8775 // The property doesn't exist - throw exception.
8776 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008777 isolate->factory()->NewReferenceError("not_defined",
8778 HandleVector(&name, 1));
8779 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008780 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008781 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008782 return MakePair(isolate->heap()->undefined_value(),
8783 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008784 }
8785}
8786
8787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008788RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008789 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790}
8791
8792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008793RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008794 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795}
8796
8797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008798RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008799 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008800 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008802 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008803 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8804 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008805 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8806 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8807 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808
8809 int index;
8810 PropertyAttributes attributes;
8811 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008812 BindingFlags binding_flags;
8813 Handle<Object> holder = context->Lookup(name,
8814 flags,
8815 &index,
8816 &attributes,
8817 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818
8819 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008820 // The property was found in a context slot.
8821 Handle<Context> context = Handle<Context>::cast(holder);
8822 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8823 context->get(index)->IsTheHole()) {
8824 Handle<Object> error =
8825 isolate->factory()->NewReferenceError("not_defined",
8826 HandleVector(&name, 1));
8827 return isolate->Throw(*error);
8828 }
8829 // Ignore if read_only variable.
8830 if ((attributes & READ_ONLY) == 0) {
8831 // Context is a fixed array and set cannot fail.
8832 context->set(index, *value);
8833 } else if (strict_mode == kStrictMode) {
8834 // Setting read only property in strict mode.
8835 Handle<Object> error =
8836 isolate->factory()->NewTypeError("strict_cannot_assign",
8837 HandleVector(&name, 1));
8838 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008839 }
8840 return *value;
8841 }
8842
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008843 // Slow case: The property is not in a context slot. It is either in a
8844 // context extension object, a property of the subject of a with, or a
8845 // property of the global object.
8846 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008848 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008849 // The property exists on the holder.
8850 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008851 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008852 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008854
8855 if (strict_mode == kStrictMode) {
8856 // Throw in strict mode (assignment to undefined variable).
8857 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008858 isolate->factory()->NewReferenceError(
8859 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008860 return isolate->Throw(*error);
8861 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008862 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008864 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 }
8866
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008867 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008868 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008869 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008870 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008871 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008872 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008873 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008874 // Setting read only property in strict mode.
8875 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008876 isolate->factory()->NewTypeError(
8877 "strict_cannot_assign", HandleVector(&name, 1));
8878 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879 }
8880 return *value;
8881}
8882
8883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008884RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008885 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886 ASSERT(args.length() == 1);
8887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008888 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889}
8890
8891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008892RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894 ASSERT(args.length() == 1);
8895
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008896 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008897}
8898
8899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008900RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008901 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008903}
8904
8905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008906RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008908 ASSERT(args.length() == 1);
8909
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008910 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008911 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 isolate->factory()->NewReferenceError("not_defined",
8913 HandleVector(&name, 1));
8914 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915}
8916
8917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008918RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008919 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008920
8921 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922 if (isolate->stack_guard()->IsStackOverflow()) {
8923 NoHandleAllocation na;
8924 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008925 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926
ulan@chromium.org812308e2012-02-29 15:58:45 +00008927 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928}
8929
8930
yangguo@chromium.org56454712012-02-16 15:33:53 +00008931RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8932 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008933 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008934}
8935
8936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008937static int StackSize() {
8938 int n = 0;
8939 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8940 return n;
8941}
8942
8943
8944static void PrintTransition(Object* result) {
8945 // indentation
8946 { const int nmax = 80;
8947 int n = StackSize();
8948 if (n <= nmax)
8949 PrintF("%4d:%*s", n, n, "");
8950 else
8951 PrintF("%4d:%*s", n, nmax, "...");
8952 }
8953
8954 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008955 JavaScriptFrame::PrintTop(stdout, true, false);
8956 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 } else {
8958 // function result
8959 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008960 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961 PrintF("\n");
8962 }
8963}
8964
8965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008966RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008967 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008968 NoHandleAllocation ha;
8969 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008970 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971}
8972
8973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008974RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 NoHandleAllocation ha;
8976 PrintTransition(args[0]);
8977 return args[0]; // return TOS
8978}
8979
8980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008981RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 NoHandleAllocation ha;
8983 ASSERT(args.length() == 1);
8984
8985#ifdef DEBUG
8986 if (args[0]->IsString()) {
8987 // If we have a string, assume it's a code "marker"
8988 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008989 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008991 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8992 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993 } else {
8994 PrintF("DebugPrint: ");
8995 }
8996 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008997 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008998 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008999 HeapObject::cast(args[0])->map()->Print();
9000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009002 // ShortPrint is available in release mode. Print is not.
9003 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004#endif
9005 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009006 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007
9008 return args[0]; // return TOS
9009}
9010
9011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009012RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009013 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 isolate->PrintStack();
9016 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017}
9018
9019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009020RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009022 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023
9024 // According to ECMA-262, section 15.9.1, page 117, the precision of
9025 // the number in a Date object representing a particular instant in
9026 // time is milliseconds. Therefore, we floor the result of getting
9027 // the OS time.
9028 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009029 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030}
9031
9032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009033RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009034 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009035 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009036
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009037 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009038 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009040 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009041
9042 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009043 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009044 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009045 RUNTIME_ASSERT(output->HasFastElements());
9046
9047 AssertNoAllocation no_allocation;
9048
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009049 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009050 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9051 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009052 String::FlatContent str_content = str->GetFlatContent();
9053 if (str_content.IsAscii()) {
9054 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009055 output_array,
9056 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009058 ASSERT(str_content.IsTwoByte());
9059 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009060 output_array,
9061 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009062 }
9063
9064 if (result) {
9065 return *output;
9066 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 }
9069}
9070
9071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009072RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073 NoHandleAllocation ha;
9074 ASSERT(args.length() == 1);
9075
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009076 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009077 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9078 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009079 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009080}
9081
9082
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009083RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084 NoHandleAllocation ha;
9085 ASSERT(args.length() == 1);
9086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009087 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009088 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9089
9090 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009091}
9092
9093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009094RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009095 ASSERT(args.length() == 1);
9096 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009098 return JSGlobalObject::cast(global)->global_receiver();
9099}
9100
9101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009102RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009103 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009104 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009105 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009106
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009107 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009108 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009109 Handle<Object> result;
9110 if (source->IsSeqAsciiString()) {
9111 result = JsonParser<true>::Parse(source);
9112 } else {
9113 result = JsonParser<false>::Parse(source);
9114 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009115 if (result.is_null()) {
9116 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009117 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009118 return Failure::Exception();
9119 }
9120 return *result;
9121}
9122
9123
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009124bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9125 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009126 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9127 // Check with callback if set.
9128 AllowCodeGenerationFromStringsCallback callback =
9129 isolate->allow_code_gen_callback();
9130 if (callback == NULL) {
9131 // No callback set and code generation disallowed.
9132 return false;
9133 } else {
9134 // Callback set. Let it decide if code generation is allowed.
9135 VMState state(isolate, EXTERNAL);
9136 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009137 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009138}
9139
9140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009141RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009143 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009144 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009145
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009146 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009148
9149 // Check if global context allows code generation from
9150 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009151 if (context->allow_code_gen_from_strings()->IsFalse() &&
9152 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009153 return isolate->Throw(*isolate->factory()->NewError(
9154 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9155 }
9156
9157 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009158 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009159 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009160 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009162 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9163 context,
9164 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165 return *fun;
9166}
9167
9168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009169static ObjectPair CompileGlobalEval(Isolate* isolate,
9170 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009171 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009172 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009173 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009174 Handle<Context> context = Handle<Context>(isolate->context());
9175 Handle<Context> global_context = Handle<Context>(context->global_context());
9176
9177 // Check if global context allows code generation from
9178 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009179 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9180 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009181 isolate->Throw(*isolate->factory()->NewError(
9182 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9183 return MakePair(Failure::Exception(), NULL);
9184 }
9185
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009186 // Deal with a normal eval call with a string argument. Compile it
9187 // and return the compiled function bound in the local context.
9188 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9189 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009190 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009191 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009192 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009193 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009194 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009195 Handle<JSFunction> compiled =
9196 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009197 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009198 return MakePair(*compiled, *receiver);
9199}
9200
9201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009202RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009203 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009205 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009206 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009207
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009208 // If "eval" didn't refer to the original GlobalEval, it's not a
9209 // direct call to eval.
9210 // (And even if it is, but the first argument isn't a string, just let
9211 // execution default to an indirect call to eval, which will also return
9212 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009214 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009215 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009216 }
9217
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009218 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009219 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009220 return CompileGlobalEval(isolate,
9221 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009222 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009223 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009224 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009225}
9226
9227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009228RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229 // This utility adjusts the property attributes for newly created Function
9230 // object ("new Function(...)") by changing the map.
9231 // All it does is changing the prototype property to enumerable
9232 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009235 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009237 Handle<Map> map = func->shared()->is_classic_mode()
9238 ? isolate->function_instance_map()
9239 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240
9241 ASSERT(func->map()->instance_type() == map->instance_type());
9242 ASSERT(func->map()->instance_size() == map->instance_size());
9243 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 return *func;
9245}
9246
9247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009248RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009249 // Allocate a block of memory in NewSpace (filled with a filler).
9250 // Use as fallback for allocation in generated code when NewSpace
9251 // is full.
9252 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009253 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009254 int size = size_smi->value();
9255 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9256 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 Heap* heap = isolate->heap();
9258 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009259 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009260 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009262 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009263 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009264 }
9265 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009266 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009267}
9268
9269
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009270// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009271// array. Returns true if the element was pushed on the stack and
9272// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009273RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009274 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009275 CONVERT_ARG_CHECKED(JSArray, array, 0);
9276 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009277 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009278 int length = Smi::cast(array->length())->value();
9279 FixedArray* elements = FixedArray::cast(array->elements());
9280 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009281 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009282 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009283 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009284 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009285 { MaybeObject* maybe_obj =
9286 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009287 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9288 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009289 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009290}
9291
9292
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009293/**
9294 * A simple visitor visits every element of Array's.
9295 * The backend storage can be a fixed array for fast elements case,
9296 * or a dictionary for sparse array. Since Dictionary is a subtype
9297 * of FixedArray, the class can be used by both fast and slow cases.
9298 * The second parameter of the constructor, fast_elements, specifies
9299 * whether the storage is a FixedArray or Dictionary.
9300 *
9301 * An index limit is used to deal with the situation that a result array
9302 * length overflows 32-bit non-negative integer.
9303 */
9304class ArrayConcatVisitor {
9305 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009306 ArrayConcatVisitor(Isolate* isolate,
9307 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009308 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009309 isolate_(isolate),
9310 storage_(Handle<FixedArray>::cast(
9311 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009312 index_offset_(0u),
9313 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009314
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009315 ~ArrayConcatVisitor() {
9316 clear_storage();
9317 }
9318
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009319 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009320 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009321 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009322
9323 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009324 if (index < static_cast<uint32_t>(storage_->length())) {
9325 storage_->set(index, *elm);
9326 return;
9327 }
9328 // Our initial estimate of length was foiled, possibly by
9329 // getters on the arrays increasing the length of later arrays
9330 // during iteration.
9331 // This shouldn't happen in anything but pathological cases.
9332 SetDictionaryMode(index);
9333 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009334 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009335 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009336 Handle<SeededNumberDictionary> dict(
9337 SeededNumberDictionary::cast(*storage_));
9338 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009339 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009340 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009341 // Dictionary needed to grow.
9342 clear_storage();
9343 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009344 }
9345}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009346
9347 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009348 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9349 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009350 } else {
9351 index_offset_ += delta;
9352 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009353 }
9354
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009355 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009356 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009357 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009359 Handle<Map> map;
9360 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009361 map = isolate_->factory()->GetElementsTransitionMap(array,
9362 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009363 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009364 map = isolate_->factory()->GetElementsTransitionMap(array,
9365 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009366 }
9367 array->set_map(*map);
9368 array->set_length(*length);
9369 array->set_elements(*storage_);
9370 return array;
9371 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009372
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009373 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009374 // Convert storage to dictionary mode.
9375 void SetDictionaryMode(uint32_t index) {
9376 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009377 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009378 Handle<SeededNumberDictionary> slow_storage(
9379 isolate_->factory()->NewSeededNumberDictionary(
9380 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009381 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9382 for (uint32_t i = 0; i < current_length; i++) {
9383 HandleScope loop_scope;
9384 Handle<Object> element(current_storage->get(i));
9385 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009386 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009387 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009388 if (!new_storage.is_identical_to(slow_storage)) {
9389 slow_storage = loop_scope.CloseAndEscape(new_storage);
9390 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009391 }
9392 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009393 clear_storage();
9394 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009395 fast_elements_ = false;
9396 }
9397
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009398 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009399 isolate_->global_handles()->Destroy(
9400 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009401 }
9402
9403 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 storage_ = Handle<FixedArray>::cast(
9405 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009406 }
9407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009408 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009409 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009410 // Index after last seen index. Always less than or equal to
9411 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009412 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009413 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009414};
9415
9416
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009417static uint32_t EstimateElementCount(Handle<JSArray> array) {
9418 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9419 int element_count = 0;
9420 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009421 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009422 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009423 // Fast elements can't have lengths that are not representable by
9424 // a 32-bit signed integer.
9425 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9426 int fast_length = static_cast<int>(length);
9427 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9428 for (int i = 0; i < fast_length; i++) {
9429 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009430 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009431 break;
9432 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009433 case FAST_DOUBLE_ELEMENTS:
9434 // TODO(1810): Decide if it's worthwhile to implement this.
9435 UNREACHABLE();
9436 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009437 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009438 Handle<SeededNumberDictionary> dictionary(
9439 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009440 int capacity = dictionary->Capacity();
9441 for (int i = 0; i < capacity; i++) {
9442 Handle<Object> key(dictionary->KeyAt(i));
9443 if (dictionary->IsKey(*key)) {
9444 element_count++;
9445 }
9446 }
9447 break;
9448 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009449 case NON_STRICT_ARGUMENTS_ELEMENTS:
9450 case EXTERNAL_BYTE_ELEMENTS:
9451 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9452 case EXTERNAL_SHORT_ELEMENTS:
9453 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9454 case EXTERNAL_INT_ELEMENTS:
9455 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9456 case EXTERNAL_FLOAT_ELEMENTS:
9457 case EXTERNAL_DOUBLE_ELEMENTS:
9458 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009459 // External arrays are always dense.
9460 return length;
9461 }
9462 // As an estimate, we assume that the prototype doesn't contain any
9463 // inherited elements.
9464 return element_count;
9465}
9466
9467
9468
9469template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470static void IterateExternalArrayElements(Isolate* isolate,
9471 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009472 bool elements_are_ints,
9473 bool elements_are_guaranteed_smis,
9474 ArrayConcatVisitor* visitor) {
9475 Handle<ExternalArrayClass> array(
9476 ExternalArrayClass::cast(receiver->elements()));
9477 uint32_t len = static_cast<uint32_t>(array->length());
9478
9479 ASSERT(visitor != NULL);
9480 if (elements_are_ints) {
9481 if (elements_are_guaranteed_smis) {
9482 for (uint32_t j = 0; j < len; j++) {
9483 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009484 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009485 visitor->visit(j, e);
9486 }
9487 } else {
9488 for (uint32_t j = 0; j < len; j++) {
9489 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009490 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009491 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9492 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9493 visitor->visit(j, e);
9494 } else {
9495 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009496 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009497 visitor->visit(j, e);
9498 }
9499 }
9500 }
9501 } else {
9502 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009503 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009504 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009505 visitor->visit(j, e);
9506 }
9507 }
9508}
9509
9510
9511// Used for sorting indices in a List<uint32_t>.
9512static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9513 uint32_t a = *ap;
9514 uint32_t b = *bp;
9515 return (a == b) ? 0 : (a < b) ? -1 : 1;
9516}
9517
9518
9519static void CollectElementIndices(Handle<JSObject> object,
9520 uint32_t range,
9521 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009522 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009523 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009524 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009525 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009526 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9527 uint32_t length = static_cast<uint32_t>(elements->length());
9528 if (range < length) length = range;
9529 for (uint32_t i = 0; i < length; i++) {
9530 if (!elements->get(i)->IsTheHole()) {
9531 indices->Add(i);
9532 }
9533 }
9534 break;
9535 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009536 case FAST_DOUBLE_ELEMENTS: {
9537 // TODO(1810): Decide if it's worthwhile to implement this.
9538 UNREACHABLE();
9539 break;
9540 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009541 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009542 Handle<SeededNumberDictionary> dict(
9543 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009544 uint32_t capacity = dict->Capacity();
9545 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009546 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009547 Handle<Object> k(dict->KeyAt(j));
9548 if (dict->IsKey(*k)) {
9549 ASSERT(k->IsNumber());
9550 uint32_t index = static_cast<uint32_t>(k->Number());
9551 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009552 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009553 }
9554 }
9555 }
9556 break;
9557 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009558 default: {
9559 int dense_elements_length;
9560 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009561 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009562 dense_elements_length =
9563 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009564 break;
9565 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009566 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009567 dense_elements_length =
9568 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009569 break;
9570 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009571 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009572 dense_elements_length =
9573 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009574 break;
9575 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009576 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009577 dense_elements_length =
9578 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009579 break;
9580 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009581 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009582 dense_elements_length =
9583 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009584 break;
9585 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009586 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009587 dense_elements_length =
9588 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009589 break;
9590 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009591 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009592 dense_elements_length =
9593 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009594 break;
9595 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009596 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009597 dense_elements_length =
9598 ExternalFloatArray::cast(object->elements())->length();
9599 break;
9600 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009601 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009602 dense_elements_length =
9603 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009604 break;
9605 }
9606 default:
9607 UNREACHABLE();
9608 dense_elements_length = 0;
9609 break;
9610 }
9611 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9612 if (range <= length) {
9613 length = range;
9614 // We will add all indices, so we might as well clear it first
9615 // and avoid duplicates.
9616 indices->Clear();
9617 }
9618 for (uint32_t i = 0; i < length; i++) {
9619 indices->Add(i);
9620 }
9621 if (length == range) return; // All indices accounted for already.
9622 break;
9623 }
9624 }
9625
9626 Handle<Object> prototype(object->GetPrototype());
9627 if (prototype->IsJSObject()) {
9628 // The prototype will usually have no inherited element indices,
9629 // but we have to check.
9630 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9631 }
9632}
9633
9634
9635/**
9636 * A helper function that visits elements of a JSArray in numerical
9637 * order.
9638 *
9639 * The visitor argument called for each existing element in the array
9640 * with the element index and the element's value.
9641 * Afterwards it increments the base-index of the visitor by the array
9642 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009643 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009644 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645static bool IterateElements(Isolate* isolate,
9646 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009647 ArrayConcatVisitor* visitor) {
9648 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9649 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009650 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009651 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 // Run through the elements FixedArray and use HasElement and GetElement
9653 // to check the prototype for missing elements.
9654 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9655 int fast_length = static_cast<int>(length);
9656 ASSERT(fast_length <= elements->length());
9657 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 HandleScope loop_scope(isolate);
9659 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009660 if (!element_value->IsTheHole()) {
9661 visitor->visit(j, element_value);
9662 } else if (receiver->HasElement(j)) {
9663 // Call GetElement on receiver, not its prototype, or getters won't
9664 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009665 element_value = Object::GetElement(receiver, j);
9666 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009667 visitor->visit(j, element_value);
9668 }
9669 }
9670 break;
9671 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009672 case FAST_DOUBLE_ELEMENTS: {
9673 // TODO(1810): Decide if it's worthwhile to implement this.
9674 UNREACHABLE();
9675 break;
9676 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009677 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009678 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009679 List<uint32_t> indices(dict->Capacity() / 2);
9680 // Collect all indices in the object and the prototypes less
9681 // than length. This might introduce duplicates in the indices list.
9682 CollectElementIndices(receiver, length, &indices);
9683 indices.Sort(&compareUInt32);
9684 int j = 0;
9685 int n = indices.length();
9686 while (j < n) {
9687 HandleScope loop_scope;
9688 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009689 Handle<Object> element = Object::GetElement(receiver, index);
9690 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009691 visitor->visit(index, element);
9692 // Skip to next different index (i.e., omit duplicates).
9693 do {
9694 j++;
9695 } while (j < n && indices[j] == index);
9696 }
9697 break;
9698 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009699 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009700 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9701 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009702 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009703 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 visitor->visit(j, e);
9705 }
9706 break;
9707 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009708 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009709 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009710 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 break;
9712 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009713 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009715 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009716 break;
9717 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009718 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009719 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009721 break;
9722 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009723 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009724 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009725 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 break;
9727 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009728 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009730 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 break;
9732 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009733 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009734 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009736 break;
9737 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009738 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009739 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009740 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 break;
9742 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009743 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009744 IterateExternalArrayElements<ExternalDoubleArray, double>(
9745 isolate, receiver, false, false, visitor);
9746 break;
9747 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009748 default:
9749 UNREACHABLE();
9750 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009751 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009752 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009753 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009754}
9755
9756
9757/**
9758 * Array::concat implementation.
9759 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009760 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009761 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009762 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009763RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009764 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009766
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009767 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009768 int argument_count = static_cast<int>(arguments->length()->Number());
9769 RUNTIME_ASSERT(arguments->HasFastElements());
9770 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009771
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009772 // Pass 1: estimate the length and number of elements of the result.
9773 // The actual length can be larger if any of the arguments have getters
9774 // that mutate other arguments (but will otherwise be precise).
9775 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009776
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009777 uint32_t estimate_result_length = 0;
9778 uint32_t estimate_nof_elements = 0;
9779 {
9780 for (int i = 0; i < argument_count; i++) {
9781 HandleScope loop_scope;
9782 Handle<Object> obj(elements->get(i));
9783 uint32_t length_estimate;
9784 uint32_t element_estimate;
9785 if (obj->IsJSArray()) {
9786 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009787 // TODO(1810): Find out if it's worthwhile to properly support
9788 // arbitrary ElementsKinds. For now, pessimistically transition to
9789 // FAST_ELEMENTS.
9790 if (array->HasFastDoubleElements()) {
9791 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009792 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009793 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009794 length_estimate =
9795 static_cast<uint32_t>(array->length()->Number());
9796 element_estimate =
9797 EstimateElementCount(array);
9798 } else {
9799 length_estimate = 1;
9800 element_estimate = 1;
9801 }
9802 // Avoid overflows by capping at kMaxElementCount.
9803 if (JSObject::kMaxElementCount - estimate_result_length <
9804 length_estimate) {
9805 estimate_result_length = JSObject::kMaxElementCount;
9806 } else {
9807 estimate_result_length += length_estimate;
9808 }
9809 if (JSObject::kMaxElementCount - estimate_nof_elements <
9810 element_estimate) {
9811 estimate_nof_elements = JSObject::kMaxElementCount;
9812 } else {
9813 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009814 }
9815 }
9816 }
9817
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009818 // If estimated number of elements is more than half of length, a
9819 // fixed array (fast case) is more time and space-efficient than a
9820 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009822
9823 Handle<FixedArray> storage;
9824 if (fast_case) {
9825 // The backing storage array must have non-existing elements to
9826 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009827 storage = isolate->factory()->NewFixedArrayWithHoles(
9828 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009829 } else {
9830 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9831 uint32_t at_least_space_for = estimate_nof_elements +
9832 (estimate_nof_elements >> 2);
9833 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009834 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009835 }
9836
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009837 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009838
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 for (int i = 0; i < argument_count; i++) {
9840 Handle<Object> obj(elements->get(i));
9841 if (obj->IsJSArray()) {
9842 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009843 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009844 return Failure::Exception();
9845 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009846 } else {
9847 visitor.visit(0, obj);
9848 visitor.increase_index_offset(1);
9849 }
9850 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009851
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009852 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009853}
9854
9855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856// This will not allocate (flatten the string), but it may run
9857// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009858RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859 NoHandleAllocation ha;
9860 ASSERT(args.length() == 1);
9861
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009862 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863 StringInputBuffer buffer(string);
9864 while (buffer.has_more()) {
9865 uint16_t character = buffer.GetNext();
9866 PrintF("%c", character);
9867 }
9868 return string;
9869}
9870
ager@chromium.org5ec48922009-05-05 07:25:34 +00009871// Moves all own elements of an object, that are below a limit, to positions
9872// starting at zero. All undefined values are placed after non-undefined values,
9873// and are followed by non-existing element. Does not change the length
9874// property.
9875// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009876RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009877 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009878 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009879 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9880 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009881}
9882
9883
9884// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009885RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009886 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009887 CONVERT_ARG_CHECKED(JSArray, from, 0);
9888 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009889 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009890 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009891 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009892 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9893 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009894 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009895 } else if (new_elements->map() ==
9896 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009897 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009898 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009899 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009900 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009901 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009902 Object* new_map;
9903 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009904 to->set_map(Map::cast(new_map));
9905 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009907 Object* obj;
9908 { MaybeObject* maybe_obj = from->ResetElements();
9909 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9910 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009911 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 return to;
9913}
9914
9915
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009916// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009917RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009919 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009920 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009921 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009922 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9923 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009924 } else if (object->IsJSArray()) {
9925 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009926 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009927 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009928 }
9929}
9930
9931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009932RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009934
9935 ASSERT_EQ(3, args.length());
9936
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009937 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009938 Handle<Object> key1 = args.at<Object>(1);
9939 Handle<Object> key2 = args.at<Object>(2);
9940
9941 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009942 if (!key1->ToArrayIndex(&index1)
9943 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009944 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009945 }
9946
ager@chromium.orgac091b72010-05-05 07:34:42 +00009947 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009948 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009949 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009950 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009951 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009952
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009953 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009954 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009955 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009956 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009959}
9960
9961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009963// might have elements. Can either return keys (positive integers) or
9964// intervals (pair of a negative integer (-start-1) followed by a
9965// positive (length)) or undefined values.
9966// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009967RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009968 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009969 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009970 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009972 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973 // Create an array and get all the keys into it, then remove all the
9974 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009975 bool threw = false;
9976 Handle<FixedArray> keys =
9977 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9978 if (threw) return Failure::Exception();
9979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009980 int keys_length = keys->length();
9981 for (int i = 0; i < keys_length; i++) {
9982 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009983 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009984 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 // Zap invalid keys.
9986 keys->set_undefined(i);
9987 }
9988 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009989 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009991 ASSERT(array->HasFastElements() ||
9992 array->HasFastSmiOnlyElements() ||
9993 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009994 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009996 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009997 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009998 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009999 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010000 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010001 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010002 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 }
10006}
10007
10008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010009RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010011 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10012 CONVERT_ARG_CHECKED(String, name, 1);
10013 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010014 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10015 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010016}
10017
10018
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010019#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010020RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010021 ASSERT(args.length() == 0);
10022 return Execution::DebugBreakHelper();
10023}
10024
10025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010026// Helper functions for wrapping and unwrapping stack frame ids.
10027static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010028 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029 return Smi::FromInt(id >> 2);
10030}
10031
10032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010033static StackFrame::Id UnwrapFrameId(int wrapped) {
10034 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035}
10036
10037
10038// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010039// args[0]: debug event listener function to set or null or undefined for
10040// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010041// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010042RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010043 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010044 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10045 args[0]->IsUndefined() ||
10046 args[0]->IsNull());
10047 Handle<Object> callback = args.at<Object>(0);
10048 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010049 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052}
10053
10054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010055RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010056 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 isolate->stack_guard()->DebugBreak();
10058 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010059}
10060
10061
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010062static MaybeObject* DebugLookupResultValue(Heap* heap,
10063 Object* receiver,
10064 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010065 LookupResult* result,
10066 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010067 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010069 case NORMAL:
10070 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010071 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 }
10074 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010075 case FIELD:
10076 value =
10077 JSObject::cast(
10078 result->holder())->FastPropertyAt(result->GetFieldIndex());
10079 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010080 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010081 }
10082 return value;
10083 case CONSTANT_FUNCTION:
10084 return result->GetConstantFunction();
10085 case CALLBACKS: {
10086 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010087 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010088 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10089 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010090 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010091 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010092 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093 maybe_value = heap->isolate()->pending_exception();
10094 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010095 if (caught_exception != NULL) {
10096 *caught_exception = true;
10097 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010098 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010099 }
10100 return value;
10101 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010103 }
10104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010106 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010107 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010108 case CONSTANT_TRANSITION:
10109 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010110 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010111 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010113 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010115 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117}
10118
10119
ager@chromium.org32912102009-01-16 10:38:43 +000010120// Get debugger related details for an object property.
10121// args[0]: object holding property
10122// args[1]: name of the property
10123//
10124// The array returned contains the following information:
10125// 0: Property value
10126// 1: Property details
10127// 2: Property value is exception
10128// 3: Getter function if defined
10129// 4: Setter function if defined
10130// Items 2-4 are only filled if the property has either a getter or a setter
10131// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010132RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134
10135 ASSERT(args.length() == 2);
10136
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010137 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10138 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010139
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010140 // Make sure to set the current context to the context before the debugger was
10141 // entered (if the debugger is entered). The reason for switching context here
10142 // is that for some property lookups (accessors and interceptors) callbacks
10143 // into the embedding application can occour, and the embedding application
10144 // could have the assumption that its own global context is the current
10145 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010146 SaveContext save(isolate);
10147 if (isolate->debug()->InDebugger()) {
10148 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010149 }
10150
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010151 // Skip the global proxy as it has no properties and always delegates to the
10152 // real global object.
10153 if (obj->IsJSGlobalProxy()) {
10154 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10155 }
10156
10157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010158 // Check if the name is trivially convertible to an index and get the element
10159 // if so.
10160 uint32_t index;
10161 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010162 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010163 Object* element_or_char;
10164 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010165 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010166 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10167 return maybe_element_or_char;
10168 }
10169 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010170 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010171 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010172 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173 }
10174
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010175 // Find the number of objects making up this.
10176 int length = LocalPrototypeChainLength(*obj);
10177
10178 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010179 Handle<JSObject> jsproto = obj;
10180 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010181 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010182 jsproto->LocalLookup(*name, &result);
10183 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010184 // LookupResult is not GC safe as it holds raw object pointers.
10185 // GC can happen later in this code so put the required fields into
10186 // local variables using handles when required for later use.
10187 PropertyType result_type = result.type();
10188 Handle<Object> result_callback_obj;
10189 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10191 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010192 }
10193 Smi* property_details = result.GetPropertyDetails().AsSmi();
10194 // DebugLookupResultValue can cause GC so details from LookupResult needs
10195 // to be copied to handles before this.
10196 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010197 Object* raw_value;
10198 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 DebugLookupResultValue(isolate->heap(), *obj, *name,
10200 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010201 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010203 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010204
10205 // If the callback object is a fixed array then it contains JavaScript
10206 // getter and/or setter.
10207 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010208 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010209 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010210 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010211 details->set(0, *value);
10212 details->set(1, property_details);
10213 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010214 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010215 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010216 details->set(3, accessors->SafeGet(ACCESSOR_GETTER));
10217 details->set(4, accessors->SafeGet(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010218 }
10219
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010221 }
10222 if (i < length - 1) {
10223 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10224 }
10225 }
10226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228}
10229
10230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010231RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233
10234 ASSERT(args.length() == 2);
10235
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010236 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10237 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010239 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 obj->Lookup(*name, &result);
10241 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010242 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245}
10246
10247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248// Return the property type calculated from the property details.
10249// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010250RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010252 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10253 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254}
10255
10256
10257// Return the property attribute calculated from the property details.
10258// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010259RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010261 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10262 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263}
10264
10265
10266// Return the property insertion index calculated from the property details.
10267// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010268RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010270 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10271 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272}
10273
10274
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275// Return property value from named interceptor.
10276// args[0]: object
10277// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010278RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010279 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010281 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010283 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284
10285 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010286 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287}
10288
10289
10290// Return element value from indexed interceptor.
10291// args[0]: object
10292// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010293RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010294 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010296 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10298 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10299
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010300 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301}
10302
10303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010304RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305 ASSERT(args.length() >= 1);
10306 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010307 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 if (isolate->debug()->break_id() == 0 ||
10309 break_id != isolate->debug()->break_id()) {
10310 return isolate->Throw(
10311 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 }
10313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010314 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315}
10316
10317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010318RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010319 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320 ASSERT(args.length() == 1);
10321
10322 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010323 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010324 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10325 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010326 if (!maybe_result->ToObject(&result)) return maybe_result;
10327 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328
10329 // Count all frames which are relevant to debugging stack trace.
10330 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010332 if (id == StackFrame::NO_ID) {
10333 // If there is no JavaScript stack frame count is 0.
10334 return Smi::FromInt(0);
10335 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010336
10337 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10338 n += it.frame()->GetInlineCount();
10339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010340 return Smi::FromInt(n);
10341}
10342
10343
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010344class FrameInspector {
10345 public:
10346 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010347 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010348 Isolate* isolate)
10349 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10350 // Calculate the deoptimized frame.
10351 if (frame->is_optimized()) {
10352 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010353 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010354 }
10355 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010356 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010357 is_optimized_ = frame_->is_optimized();
10358 }
10359
10360 ~FrameInspector() {
10361 // Get rid of the calculated deoptimized frame if any.
10362 if (deoptimized_frame_ != NULL) {
10363 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10364 isolate_);
10365 }
10366 }
10367
10368 int GetParametersCount() {
10369 return is_optimized_
10370 ? deoptimized_frame_->parameters_count()
10371 : frame_->ComputeParametersCount();
10372 }
10373 int expression_count() { return deoptimized_frame_->expression_count(); }
10374 Object* GetFunction() {
10375 return is_optimized_
10376 ? deoptimized_frame_->GetFunction()
10377 : frame_->function();
10378 }
10379 Object* GetParameter(int index) {
10380 return is_optimized_
10381 ? deoptimized_frame_->GetParameter(index)
10382 : frame_->GetParameter(index);
10383 }
10384 Object* GetExpression(int index) {
10385 return is_optimized_
10386 ? deoptimized_frame_->GetExpression(index)
10387 : frame_->GetExpression(index);
10388 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010389 int GetSourcePosition() {
10390 return is_optimized_
10391 ? deoptimized_frame_->GetSourcePosition()
10392 : frame_->LookupCode()->SourcePosition(frame_->pc());
10393 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010394 bool IsConstructor() {
10395 return is_optimized_ && !is_bottommost_
10396 ? deoptimized_frame_->HasConstructStub()
10397 : frame_->IsConstructor();
10398 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010399
10400 // To inspect all the provided arguments the frame might need to be
10401 // replaced with the arguments frame.
10402 void SetArgumentsFrame(JavaScriptFrame* frame) {
10403 ASSERT(has_adapted_arguments_);
10404 frame_ = frame;
10405 is_optimized_ = frame_->is_optimized();
10406 ASSERT(!is_optimized_);
10407 }
10408
10409 private:
10410 JavaScriptFrame* frame_;
10411 DeoptimizedFrameInfo* deoptimized_frame_;
10412 Isolate* isolate_;
10413 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010414 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010415 bool has_adapted_arguments_;
10416
10417 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10418};
10419
10420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421static const int kFrameDetailsFrameIdIndex = 0;
10422static const int kFrameDetailsReceiverIndex = 1;
10423static const int kFrameDetailsFunctionIndex = 2;
10424static const int kFrameDetailsArgumentCountIndex = 3;
10425static const int kFrameDetailsLocalCountIndex = 4;
10426static const int kFrameDetailsSourcePositionIndex = 5;
10427static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010428static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010429static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010430static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010431
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010432
10433static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10434 JavaScriptFrame* frame) {
10435 SaveContext* save = isolate->save_context();
10436 while (save != NULL && !save->IsBelowFrame(frame)) {
10437 save = save->prev();
10438 }
10439 ASSERT(save != NULL);
10440 return save;
10441}
10442
10443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010444// Return an array with frame details
10445// args[0]: number: break id
10446// args[1]: number: frame index
10447//
10448// The array returned contains the following information:
10449// 0: Frame id
10450// 1: Receiver
10451// 2: Function
10452// 3: Argument count
10453// 4: Local count
10454// 5: Source position
10455// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010456// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010457// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010458// Arguments name, value
10459// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010460// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010461RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010463 ASSERT(args.length() == 2);
10464
10465 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010466 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010467 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10468 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010469 if (!maybe_check->ToObject(&check)) return maybe_check;
10470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473
10474 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010475 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010476 if (id == StackFrame::NO_ID) {
10477 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010479 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010482 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010484 if (index < count + it.frame()->GetInlineCount()) break;
10485 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010489 bool is_optimized = it.frame()->is_optimized();
10490
10491 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10492 if (is_optimized) {
10493 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010494 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010495 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010496 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010497
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498 // Traverse the saved contexts chain to find the active context for the
10499 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010500 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501
10502 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010505 // Find source position in unoptimized code.
10506 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507
ulan@chromium.org967e2702012-02-28 09:49:15 +000010508 // Check for constructor frame.
10509 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010511 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010512 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010513 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010514 Handle<ScopeInfo> scope_info(shared->scope_info());
10515 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517 // Get the locals names and values into a temporary array.
10518 //
10519 // TODO(1240907): Hide compiler-introduced stack variables
10520 // (e.g. .result)? For users of the debugger, they will probably be
10521 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010523 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010525 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010526 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010527 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010528 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010529 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010530 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010531 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010532 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010533 // Get the context containing declarations.
10534 Handle<Context> context(
10535 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010536 for (; i < scope_info->LocalCount(); ++i) {
10537 Handle<String> name(scope_info->LocalName(i));
10538 VariableMode mode;
10539 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010540 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010541 locals->set(i * 2 + 1, context->get(
10542 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010543 }
10544 }
10545
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010546 // Check whether this frame is positioned at return. If not top
10547 // frame or if the frame is optimized it cannot be at a return.
10548 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010549 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010550 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010551 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010552
10553 // If positioned just before return find the value to be returned and add it
10554 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010555 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010556 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010557 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010558 Address internal_frame_sp = NULL;
10559 while (!it2.done()) {
10560 if (it2.frame()->is_internal()) {
10561 internal_frame_sp = it2.frame()->sp();
10562 } else {
10563 if (it2.frame()->is_java_script()) {
10564 if (it2.frame()->id() == it.frame()->id()) {
10565 // The internal frame just before the JavaScript frame contains the
10566 // value to return on top. A debug break at return will create an
10567 // internal frame to store the return value (eax/rax/r0) before
10568 // entering the debug break exit frame.
10569 if (internal_frame_sp != NULL) {
10570 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010571 Handle<Object>(Memory::Object_at(internal_frame_sp),
10572 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010573 break;
10574 }
10575 }
10576 }
10577
10578 // Indicate that the previous frame was not an internal frame.
10579 internal_frame_sp = NULL;
10580 }
10581 it2.Advance();
10582 }
10583 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584
10585 // Now advance to the arguments adapter frame (if any). It contains all
10586 // the provided parameters whereas the function frame always have the number
10587 // of arguments matching the functions parameters. The rest of the
10588 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010589 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010590 it.AdvanceToArgumentsFrame();
10591 frame_inspector.SetArgumentsFrame(it.frame());
10592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593
10594 // Find the number of arguments to fill. At least fill the number of
10595 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010596 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010597 if (argument_count < frame_inspector.GetParametersCount()) {
10598 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 }
10600
10601 // Calculate the size of the result.
10602 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010603 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010604 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606
10607 // Add the frame id.
10608 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10609
10610 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010611 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612
10613 // Add the arguments count.
10614 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10615
10616 // Add the locals count
10617 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010618 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619
10620 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010621 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10623 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010624 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625 }
10626
10627 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010630 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010631 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010632
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010633 // Add flags to indicate information on whether this frame is
10634 // bit 0: invoked in the debugger context.
10635 // bit 1: optimized frame.
10636 // bit 2: inlined in optimized frame
10637 int flags = 0;
10638 if (*save->context() == *isolate->debug()->debug_context()) {
10639 flags |= 1 << 0;
10640 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010641 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010642 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010643 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010644 }
10645 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646
10647 // Fill the dynamic part.
10648 int details_index = kFrameDetailsFirstDynamicIndex;
10649
10650 // Add arguments name and value.
10651 for (int i = 0; i < argument_count; i++) {
10652 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010653 if (i < scope_info->ParameterCount()) {
10654 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657 }
10658
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010659 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010660 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010661 // Get the value from the stack.
10662 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010664 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665 }
10666 }
10667
10668 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010669 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670 details->set(details_index++, locals->get(i));
10671 }
10672
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010673 // Add the value being returned.
10674 if (at_return) {
10675 details->set(details_index++, *return_value);
10676 }
10677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678 // Add the receiver (same as in function frame).
10679 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10680 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010682 if (!receiver->IsJSObject() &&
10683 shared->is_classic_mode() &&
10684 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010685 // If the receiver is not a JSObject and the function is not a
10686 // builtin or strict-mode we have hit an optimization where a
10687 // value object is not converted into a wrapped JS objects. To
10688 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689 // by creating correct wrapper object based on the calling frame's
10690 // global context.
10691 it.Advance();
10692 Handle<Context> calling_frames_global_context(
10693 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 receiver =
10695 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010696 }
10697 details->set(kFrameDetailsReceiverIndex, *receiver);
10698
10699 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010700 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701}
10702
10703
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010704// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010705static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010706 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010707 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010708 Handle<Context> context,
10709 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010710 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010711 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10712 VariableMode mode;
10713 InitializationFlag init_flag;
10714 int context_index = scope_info->ContextSlotIndex(
10715 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010716
whesse@chromium.org7b260152011-06-20 15:33:18 +000010717 RETURN_IF_EMPTY_HANDLE_VALUE(
10718 isolate,
10719 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010720 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010721 Handle<Object>(context->get(context_index), isolate),
10722 NONE,
10723 kNonStrictMode),
10724 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010725 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010726
10727 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010728}
10729
10730
10731// Create a plain JSObject which materializes the local scope for the specified
10732// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010733static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010734 Isolate* isolate,
10735 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010736 FrameInspector* frame_inspector) {
10737 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010738 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010739 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010740
10741 // Allocate and initialize a JSObject with all the arguments, stack locals
10742 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010743 Handle<JSObject> local_scope =
10744 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010745
10746 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010747 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010748 Handle<Object> value(
10749 i < frame_inspector->GetParametersCount() ?
10750 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10751
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010752 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010754 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010755 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010756 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010757 NONE,
10758 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010759 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010760 }
10761
10762 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010763 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010764 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010765 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010766 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010767 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010768 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010769 NONE,
10770 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010771 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010772 }
10773
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010774 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010775 // Third fill all context locals.
10776 Handle<Context> frame_context(Context::cast(frame->context()));
10777 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010778 if (!CopyContextLocalsToScopeObject(
10779 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010780 return Handle<JSObject>();
10781 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010782
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010783 // Finally copy any properties from the function context extension.
10784 // These will be variables introduced by eval.
10785 if (function_context->closure() == *function) {
10786 if (function_context->has_extension() &&
10787 !function_context->IsGlobalContext()) {
10788 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010789 bool threw = false;
10790 Handle<FixedArray> keys =
10791 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10792 if (threw) return Handle<JSObject>();
10793
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010794 for (int i = 0; i < keys->length(); i++) {
10795 // Names of variables introduced by eval are strings.
10796 ASSERT(keys->get(i)->IsString());
10797 Handle<String> key(String::cast(keys->get(i)));
10798 RETURN_IF_EMPTY_HANDLE_VALUE(
10799 isolate,
10800 SetProperty(local_scope,
10801 key,
10802 GetProperty(ext, key),
10803 NONE,
10804 kNonStrictMode),
10805 Handle<JSObject>());
10806 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010807 }
10808 }
10809 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010810
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010811 return local_scope;
10812}
10813
10814
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010815static Handle<JSObject> MaterializeLocalScope(
10816 Isolate* isolate,
10817 JavaScriptFrame* frame,
10818 int inlined_jsframe_index) {
10819 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10820 return MaterializeLocalScopeWithFrameInspector(isolate,
10821 frame,
10822 &frame_inspector);
10823}
10824
10825
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010826// Create a plain JSObject which materializes the closure content for the
10827// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010828static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10829 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010830 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010831
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010832 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010833 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010834
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010835 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010836 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 Handle<JSObject> closure_scope =
10838 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010839
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010840 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010841 if (!CopyContextLocalsToScopeObject(
10842 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010843 return Handle<JSObject>();
10844 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010845
10846 // Finally copy any properties from the function context extension. This will
10847 // be variables introduced by eval.
10848 if (context->has_extension()) {
10849 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010850 bool threw = false;
10851 Handle<FixedArray> keys =
10852 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10853 if (threw) return Handle<JSObject>();
10854
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010855 for (int i = 0; i < keys->length(); i++) {
10856 // Names of variables introduced by eval are strings.
10857 ASSERT(keys->get(i)->IsString());
10858 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010859 RETURN_IF_EMPTY_HANDLE_VALUE(
10860 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010861 SetProperty(closure_scope,
10862 key,
10863 GetProperty(ext, key),
10864 NONE,
10865 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010866 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010867 }
10868 }
10869
10870 return closure_scope;
10871}
10872
10873
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010874// Create a plain JSObject which materializes the scope for the specified
10875// catch context.
10876static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10877 Handle<Context> context) {
10878 ASSERT(context->IsCatchContext());
10879 Handle<String> name(String::cast(context->extension()));
10880 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10881 Handle<JSObject> catch_scope =
10882 isolate->factory()->NewJSObject(isolate->object_function());
10883 RETURN_IF_EMPTY_HANDLE_VALUE(
10884 isolate,
10885 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10886 Handle<JSObject>());
10887 return catch_scope;
10888}
10889
10890
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010891// Create a plain JSObject which materializes the block scope for the specified
10892// block context.
10893static Handle<JSObject> MaterializeBlockScope(
10894 Isolate* isolate,
10895 Handle<Context> context) {
10896 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010897 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010898
10899 // Allocate and initialize a JSObject with all the arguments, stack locals
10900 // heap locals and extension properties of the debugged function.
10901 Handle<JSObject> block_scope =
10902 isolate->factory()->NewJSObject(isolate->object_function());
10903
10904 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010905 if (!CopyContextLocalsToScopeObject(
10906 isolate, scope_info, context, block_scope)) {
10907 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010908 }
10909
10910 return block_scope;
10911}
10912
10913
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010914// Create a plain JSObject which materializes the module scope for the specified
10915// module context.
10916static Handle<JSObject> MaterializeModuleScope(
10917 Isolate* isolate,
10918 Handle<Context> context) {
10919 ASSERT(context->IsModuleContext());
10920 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10921
10922 // Allocate and initialize a JSObject with all the members of the debugged
10923 // module.
10924 Handle<JSObject> module_scope =
10925 isolate->factory()->NewJSObject(isolate->object_function());
10926
10927 // Fill all context locals.
10928 if (!CopyContextLocalsToScopeObject(
10929 isolate, scope_info, context, module_scope)) {
10930 return Handle<JSObject>();
10931 }
10932
10933 return module_scope;
10934}
10935
10936
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010937// Iterate over the actual scopes visible from a stack frame. The iteration
10938// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010939// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010940// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010941class ScopeIterator {
10942 public:
10943 enum ScopeType {
10944 ScopeTypeGlobal = 0,
10945 ScopeTypeLocal,
10946 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010947 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010948 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010949 ScopeTypeBlock,
10950 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010951 };
10952
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010953 ScopeIterator(Isolate* isolate,
10954 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010955 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010956 : isolate_(isolate),
10957 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010958 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010959 function_(JSFunction::cast(frame->function())),
10960 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010961 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010962
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010963 // Catch the case when the debugger stops in an internal function.
10964 Handle<SharedFunctionInfo> shared_info(function_->shared());
10965 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10966 if (shared_info->script() == isolate->heap()->undefined_value()) {
10967 while (context_->closure() == *function_) {
10968 context_ = Handle<Context>(context_->previous(), isolate_);
10969 }
10970 return;
10971 }
10972
10973 // Get the debug info (create it if it does not exist).
10974 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10975 // Return if ensuring debug info failed.
10976 return;
10977 }
10978 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10979
10980 // Find the break point where execution has stopped.
10981 BreakLocationIterator break_location_iterator(debug_info,
10982 ALL_BREAK_LOCATIONS);
10983 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10984 if (break_location_iterator.IsExit()) {
10985 // We are within the return sequence. At the momemt it is not possible to
10986 // get a source position which is consistent with the current scope chain.
10987 // Thus all nested with, catch and block contexts are skipped and we only
10988 // provide the function scope.
10989 if (scope_info->HasContext()) {
10990 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10991 } else {
10992 while (context_->closure() == *function_) {
10993 context_ = Handle<Context>(context_->previous(), isolate_);
10994 }
10995 }
10996 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10997 } else {
10998 // Reparse the code and analyze the scopes.
10999 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11000 Handle<Script> script(Script::cast(shared_info->script()));
11001 Scope* scope = NULL;
11002
11003 // Check whether we are in global, eval or function code.
11004 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11005 if (scope_info->Type() != FUNCTION_SCOPE) {
11006 // Global or eval code.
11007 CompilationInfo info(script);
11008 if (scope_info->Type() == GLOBAL_SCOPE) {
11009 info.MarkAsGlobal();
11010 } else {
11011 ASSERT(scope_info->Type() == EVAL_SCOPE);
11012 info.MarkAsEval();
11013 info.SetCallingContext(Handle<Context>(function_->context()));
11014 }
11015 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11016 scope = info.function()->scope();
11017 }
11018 } else {
11019 // Function code
11020 CompilationInfo info(shared_info);
11021 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11022 scope = info.function()->scope();
11023 }
11024 }
11025
11026 // Retrieve the scope chain for the current position.
11027 if (scope != NULL) {
11028 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11029 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11030 } else {
11031 // A failed reparse indicates that the preparser has diverged from the
11032 // parser or that the preparse data given to the initial parse has been
11033 // faulty. We fail in debug mode but in release mode we only provide the
11034 // information we get from the context chain but nothing about
11035 // completely stack allocated scopes or stack allocated locals.
11036 UNREACHABLE();
11037 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038 }
11039 }
11040
11041 // More scopes?
11042 bool Done() { return context_.is_null(); }
11043
11044 // Move to the next scope.
11045 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011046 ScopeType scope_type = Type();
11047 if (scope_type == ScopeTypeGlobal) {
11048 // The global scope is always the last in the chain.
11049 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050 context_ = Handle<Context>();
11051 return;
11052 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011053 if (nested_scope_chain_.is_empty()) {
11054 context_ = Handle<Context>(context_->previous(), isolate_);
11055 } else {
11056 if (nested_scope_chain_.last()->HasContext()) {
11057 ASSERT(context_->previous() != NULL);
11058 context_ = Handle<Context>(context_->previous(), isolate_);
11059 }
11060 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011061 }
11062 }
11063
11064 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011065 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011066 if (!nested_scope_chain_.is_empty()) {
11067 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11068 switch (scope_info->Type()) {
11069 case FUNCTION_SCOPE:
11070 ASSERT(context_->IsFunctionContext() ||
11071 !scope_info->HasContext());
11072 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011073 case MODULE_SCOPE:
11074 ASSERT(context_->IsModuleContext());
11075 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011076 case GLOBAL_SCOPE:
11077 ASSERT(context_->IsGlobalContext());
11078 return ScopeTypeGlobal;
11079 case WITH_SCOPE:
11080 ASSERT(context_->IsWithContext());
11081 return ScopeTypeWith;
11082 case CATCH_SCOPE:
11083 ASSERT(context_->IsCatchContext());
11084 return ScopeTypeCatch;
11085 case BLOCK_SCOPE:
11086 ASSERT(!scope_info->HasContext() ||
11087 context_->IsBlockContext());
11088 return ScopeTypeBlock;
11089 case EVAL_SCOPE:
11090 UNREACHABLE();
11091 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011092 }
11093 if (context_->IsGlobalContext()) {
11094 ASSERT(context_->global()->IsGlobalObject());
11095 return ScopeTypeGlobal;
11096 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011097 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098 return ScopeTypeClosure;
11099 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011100 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011101 return ScopeTypeCatch;
11102 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011103 if (context_->IsBlockContext()) {
11104 return ScopeTypeBlock;
11105 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011106 if (context_->IsModuleContext()) {
11107 return ScopeTypeModule;
11108 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011109 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011110 return ScopeTypeWith;
11111 }
11112
11113 // Return the JavaScript object with the content of the current scope.
11114 Handle<JSObject> ScopeObject() {
11115 switch (Type()) {
11116 case ScopeIterator::ScopeTypeGlobal:
11117 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011118 case ScopeIterator::ScopeTypeLocal:
11119 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011120 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011121 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011122 case ScopeIterator::ScopeTypeWith:
11123 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011124 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11125 case ScopeIterator::ScopeTypeCatch:
11126 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011127 case ScopeIterator::ScopeTypeClosure:
11128 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011130 case ScopeIterator::ScopeTypeBlock:
11131 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011132 case ScopeIterator::ScopeTypeModule:
11133 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134 }
11135 UNREACHABLE();
11136 return Handle<JSObject>();
11137 }
11138
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011139 Handle<ScopeInfo> CurrentScopeInfo() {
11140 if (!nested_scope_chain_.is_empty()) {
11141 return nested_scope_chain_.last();
11142 } else if (context_->IsBlockContext()) {
11143 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11144 } else if (context_->IsFunctionContext()) {
11145 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11146 }
11147 return Handle<ScopeInfo>::null();
11148 }
11149
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011150 // Return the context for this scope. For the local context there might not
11151 // be an actual context.
11152 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011153 if (Type() == ScopeTypeGlobal ||
11154 nested_scope_chain_.is_empty()) {
11155 return context_;
11156 } else if (nested_scope_chain_.last()->HasContext()) {
11157 return context_;
11158 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011159 return Handle<Context>();
11160 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011161 }
11162
11163#ifdef DEBUG
11164 // Debug print of the content of the current scope.
11165 void DebugPrint() {
11166 switch (Type()) {
11167 case ScopeIterator::ScopeTypeGlobal:
11168 PrintF("Global:\n");
11169 CurrentContext()->Print();
11170 break;
11171
11172 case ScopeIterator::ScopeTypeLocal: {
11173 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011174 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175 if (!CurrentContext().is_null()) {
11176 CurrentContext()->Print();
11177 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011178 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011179 if (extension->IsJSContextExtensionObject()) {
11180 extension->Print();
11181 }
11182 }
11183 }
11184 break;
11185 }
11186
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011187 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011188 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011189 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011190 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011191
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011192 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011193 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011194 CurrentContext()->extension()->Print();
11195 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011196 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011197
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011198 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011199 PrintF("Closure:\n");
11200 CurrentContext()->Print();
11201 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011202 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011203 if (extension->IsJSContextExtensionObject()) {
11204 extension->Print();
11205 }
11206 }
11207 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011208
11209 default:
11210 UNREACHABLE();
11211 }
11212 PrintF("\n");
11213 }
11214#endif
11215
11216 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011217 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011218 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011219 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011220 Handle<JSFunction> function_;
11221 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011222 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011223
11224 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11225};
11226
11227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011228RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011229 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230 ASSERT(args.length() == 2);
11231
11232 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011233 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011234 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11235 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011236 if (!maybe_check->ToObject(&check)) return maybe_check;
11237 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011238 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011239
11240 // Get the frame where the debugging is performed.
11241 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011242 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011243 JavaScriptFrame* frame = it.frame();
11244
11245 // Count the visible scopes.
11246 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011247 for (ScopeIterator it(isolate, frame, 0);
11248 !it.Done();
11249 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011250 n++;
11251 }
11252
11253 return Smi::FromInt(n);
11254}
11255
11256
11257static const int kScopeDetailsTypeIndex = 0;
11258static const int kScopeDetailsObjectIndex = 1;
11259static const int kScopeDetailsSize = 2;
11260
11261// Return an array with scope details
11262// args[0]: number: break id
11263// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011264// args[2]: number: inlined frame index
11265// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011266//
11267// The array returned contains the following information:
11268// 0: Scope type
11269// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011270RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011271 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011272 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011273
11274 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011275 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011276 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11277 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011278 if (!maybe_check->ToObject(&check)) return maybe_check;
11279 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011280 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011281 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011282 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011283
11284 // Get the frame where the debugging is performed.
11285 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011286 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011287 JavaScriptFrame* frame = frame_it.frame();
11288
11289 // Find the requested scope.
11290 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011291 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011292 for (; !it.Done() && n < index; it.Next()) {
11293 n++;
11294 }
11295 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011296 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011297 }
11298
11299 // Calculate the size of the result.
11300 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011301 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011302
11303 // Fill in scope details.
11304 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011305 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011306 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011307 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011309 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011310}
11311
11312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011313RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011315 ASSERT(args.length() == 0);
11316
11317#ifdef DEBUG
11318 // Print the scopes for the top frame.
11319 StackFrameLocator locator;
11320 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011321 for (ScopeIterator it(isolate, frame, 0);
11322 !it.Done();
11323 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011324 it.DebugPrint();
11325 }
11326#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011328}
11329
11330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011331RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011333 ASSERT(args.length() == 1);
11334
11335 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011336 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011337 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11338 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011339 if (!maybe_result->ToObject(&result)) return maybe_result;
11340 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011341
11342 // Count all archived V8 threads.
11343 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011344 for (ThreadState* thread =
11345 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011346 thread != NULL;
11347 thread = thread->Next()) {
11348 n++;
11349 }
11350
11351 // Total number of threads is current thread and archived threads.
11352 return Smi::FromInt(n + 1);
11353}
11354
11355
11356static const int kThreadDetailsCurrentThreadIndex = 0;
11357static const int kThreadDetailsThreadIdIndex = 1;
11358static const int kThreadDetailsSize = 2;
11359
11360// Return an array with thread details
11361// args[0]: number: break id
11362// args[1]: number: thread index
11363//
11364// The array returned contains the following information:
11365// 0: Is current thread?
11366// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011367RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011368 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011369 ASSERT(args.length() == 2);
11370
11371 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011372 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011373 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11374 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011375 if (!maybe_check->ToObject(&check)) return maybe_check;
11376 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011377 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11378
11379 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 Handle<FixedArray> details =
11381 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011382
11383 // Thread index 0 is current thread.
11384 if (index == 0) {
11385 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011386 details->set(kThreadDetailsCurrentThreadIndex,
11387 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011388 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011389 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011390 } else {
11391 // Find the thread with the requested index.
11392 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 ThreadState* thread =
11394 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011395 while (index != n && thread != NULL) {
11396 thread = thread->Next();
11397 n++;
11398 }
11399 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011400 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011401 }
11402
11403 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011404 details->set(kThreadDetailsCurrentThreadIndex,
11405 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011406 details->set(kThreadDetailsThreadIdIndex,
11407 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011408 }
11409
11410 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011411 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011412}
11413
11414
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011415// Sets the disable break state
11416// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011417RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011419 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011420 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 isolate->debug()->set_disable_break(disable_break);
11422 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011423}
11424
11425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011426RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011427 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011428 ASSERT(args.length() == 1);
11429
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011430 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011431 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011432 // Find the number of break points
11433 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011434 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011435 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011437 Handle<FixedArray>::cast(break_locations));
11438}
11439
11440
11441// Set a break point in a function
11442// args[0]: function
11443// args[1]: number: break source position (within the function source)
11444// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011445RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011446 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011447 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011448 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011449 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011450 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11451 RUNTIME_ASSERT(source_position >= 0);
11452 Handle<Object> break_point_object_arg = args.at<Object>(2);
11453
11454 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011455 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11456 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011457
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011458 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011459}
11460
11461
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011462Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11463 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011464 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011465 // Iterate the heap looking for SharedFunctionInfo generated from the
11466 // script. The inner most SharedFunctionInfo containing the source position
11467 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011468 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011469 // which is found is not compiled it is compiled and the heap is iterated
11470 // again as the compilation might create inner functions from the newly
11471 // compiled function and the actual requested break point might be in one of
11472 // these functions.
11473 bool done = false;
11474 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011475 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011476 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011477 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011478 { // Extra scope for iterator and no-allocation.
11479 isolate->heap()->EnsureHeapIsIterable();
11480 AssertNoAllocation no_alloc_during_heap_iteration;
11481 HeapIterator iterator;
11482 for (HeapObject* obj = iterator.next();
11483 obj != NULL; obj = iterator.next()) {
11484 if (obj->IsSharedFunctionInfo()) {
11485 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11486 if (shared->script() == *script) {
11487 // If the SharedFunctionInfo found has the requested script data and
11488 // contains the source position it is a candidate.
11489 int start_position = shared->function_token_position();
11490 if (start_position == RelocInfo::kNoPosition) {
11491 start_position = shared->start_position();
11492 }
11493 if (start_position <= position &&
11494 position <= shared->end_position()) {
11495 // If there is no candidate or this function is within the current
11496 // candidate this is the new candidate.
11497 if (target.is_null()) {
11498 target_start_position = start_position;
11499 target = shared;
11500 } else {
11501 if (target_start_position == start_position &&
11502 shared->end_position() == target->end_position()) {
11503 // If a top-level function contain only one function
11504 // declartion the source for the top-level and the
11505 // function is the same. In that case prefer the non
11506 // top-level function.
11507 if (!shared->is_toplevel()) {
11508 target_start_position = start_position;
11509 target = shared;
11510 }
11511 } else if (target_start_position <= start_position &&
11512 shared->end_position() <= target->end_position()) {
11513 // This containment check includes equality as a function
11514 // inside a top-level function can share either start or end
11515 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011516 target_start_position = start_position;
11517 target = shared;
11518 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011519 }
11520 }
11521 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011522 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011523 } // End for loop.
11524 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011526 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011527 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528 }
11529
11530 // If the candidate found is compiled we are done. NOTE: when lazy
11531 // compilation of inner functions is introduced some additional checking
11532 // needs to be done here to compile inner functions.
11533 done = target->is_compiled();
11534 if (!done) {
11535 // If the candidate is not compiled compile it to reveal any inner
11536 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011537 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011539 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540
11541 return *target;
11542}
11543
11544
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011545// Changes the state of a break point in a script and returns source position
11546// where break point was set. NOTE: Regarding performance see the NOTE for
11547// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011548// args[0]: script to set break point in
11549// args[1]: number: break source position (within the script source)
11550// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011551RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011553 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011554 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011555 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11556 RUNTIME_ASSERT(source_position >= 0);
11557 Handle<Object> break_point_object_arg = args.at<Object>(2);
11558
11559 // Get the script from the script wrapper.
11560 RUNTIME_ASSERT(wrapper->value()->IsScript());
11561 Handle<Script> script(Script::cast(wrapper->value()));
11562
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011563 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011565 if (!result->IsUndefined()) {
11566 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11567 // Find position within function. The script position might be before the
11568 // source position of the first function.
11569 int position;
11570 if (shared->start_position() > source_position) {
11571 position = 0;
11572 } else {
11573 position = source_position - shared->start_position();
11574 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011575 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011576 position += shared->start_position();
11577 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011579 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011580}
11581
11582
11583// Clear a break point
11584// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011585RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011586 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011587 ASSERT(args.length() == 1);
11588 Handle<Object> break_point_object_arg = args.at<Object>(0);
11589
11590 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011594}
11595
11596
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011597// Change the state of break on exceptions.
11598// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11599// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011600RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011601 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011603 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011604 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011605
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011606 // If the number doesn't match an enum value, the ChangeBreakOnException
11607 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608 ExceptionBreakType type =
11609 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011610 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 isolate->debug()->ChangeBreakOnException(type, enable);
11612 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011613}
11614
11615
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011616// Returns the state of break on exceptions
11617// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011618RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011620 ASSERT(args.length() == 1);
11621 RUNTIME_ASSERT(args[0]->IsNumber());
11622
11623 ExceptionBreakType type =
11624 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011626 return Smi::FromInt(result);
11627}
11628
11629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011630// Prepare for stepping
11631// args[0]: break id for checking execution state
11632// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011633// args[2]: number of times to perform the step, for step out it is the number
11634// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011635RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 ASSERT(args.length() == 3);
11638 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011639 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011640 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11641 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011642 if (!maybe_check->ToObject(&check)) return maybe_check;
11643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011644 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646 }
11647
11648 // Get the step action and check validity.
11649 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11650 if (step_action != StepIn &&
11651 step_action != StepNext &&
11652 step_action != StepOut &&
11653 step_action != StepInMin &&
11654 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011656 }
11657
11658 // Get the number of steps.
11659 int step_count = NumberToInt32(args[2]);
11660 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011661 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011662 }
11663
ager@chromium.orga1645e22009-09-09 19:27:10 +000011664 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011667 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011668 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11669 step_count);
11670 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011671}
11672
11673
11674// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011675RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011676 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011677 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 isolate->debug()->ClearStepping();
11679 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011680}
11681
11682
11683// Creates a copy of the with context chain. The copy of the context chain is
11684// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011685static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11686 Handle<JSFunction> function,
11687 Handle<Context> base,
11688 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011689 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011690 HandleScope scope(isolate);
11691 List<Handle<ScopeInfo> > scope_chain;
11692 List<Handle<Context> > context_chain;
11693
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011694 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011695 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11696 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11697 ASSERT(!it.Done());
11698 scope_chain.Add(it.CurrentScopeInfo());
11699 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011700 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011701
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011702 // At the end of the chain. Return the base context to link to.
11703 Handle<Context> context = base;
11704
11705 // Iteratively copy and or materialize the nested contexts.
11706 while (!scope_chain.is_empty()) {
11707 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11708 Handle<Context> current = context_chain.RemoveLast();
11709 ASSERT(!(scope_info->HasContext() & current.is_null()));
11710
11711 if (scope_info->Type() == CATCH_SCOPE) {
11712 Handle<String> name(String::cast(current->extension()));
11713 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11714 context =
11715 isolate->factory()->NewCatchContext(function,
11716 context,
11717 name,
11718 thrown_object);
11719 } else if (scope_info->Type() == BLOCK_SCOPE) {
11720 // Materialize the contents of the block scope into a JSObject.
11721 Handle<JSObject> block_scope_object =
11722 MaterializeBlockScope(isolate, current);
11723 if (block_scope_object.is_null()) {
11724 return Handle<Context>::null();
11725 }
11726 // Allocate a new function context for the debug evaluation and set the
11727 // extension object.
11728 Handle<Context> new_context =
11729 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11730 function);
11731 new_context->set_extension(*block_scope_object);
11732 new_context->set_previous(*context);
11733 context = new_context;
11734 } else {
11735 ASSERT(scope_info->Type() == WITH_SCOPE);
11736 ASSERT(current->IsWithContext());
11737 Handle<JSObject> extension(JSObject::cast(current->extension()));
11738 context =
11739 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011740 }
erikcorry0ad885c2011-11-21 13:51:57 +000011741 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011742
11743 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011744}
11745
11746
11747// Helper function to find or create the arguments object for
11748// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749static Handle<Object> GetArgumentsObject(Isolate* isolate,
11750 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011751 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011752 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011753 Handle<Context> function_context) {
11754 // Try to find the value of 'arguments' to pass as parameter. If it is not
11755 // found (that is the debugged function does not reference 'arguments' and
11756 // does not support eval) then create an 'arguments' object.
11757 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011758 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 }
11763 }
11764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011765 if (scope_info->HasHeapAllocatedLocals()) {
11766 VariableMode mode;
11767 InitializationFlag init_flag;
11768 index = scope_info->ContextSlotIndex(
11769 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011770 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 }
11773 }
11774
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011775 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11776 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011777 Handle<JSObject> arguments =
11778 isolate->factory()->NewArgumentsObject(function, length);
11779 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011780
11781 AssertNoAllocation no_gc;
11782 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011783 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011784 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011785 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011786 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 return arguments;
11788}
11789
11790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011791static const char kSourceStr[] =
11792 "(function(arguments,__source__){return eval(__source__);})";
11793
11794
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011795// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011796// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797// extension part has all the parameters and locals of the function on the
11798// stack frame. A function which calls eval with the code to evaluate is then
11799// compiled in this context and called in this context. As this context
11800// replaces the context of the function on the stack frame a new (empty)
11801// function is created as well to be used as the closure for the context.
11802// This function and the context acts as replacements for the function on the
11803// stack frame presenting the same view of the values of parameters and
11804// local variables as if the piece of JavaScript was evaluated at the point
11805// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011806RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011808
11809 // Check the execution state and decode arguments frame and source to be
11810 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011811 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011812 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011813 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11814 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011815 if (!maybe_check_result->ToObject(&check_result)) {
11816 return maybe_check_result;
11817 }
11818 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011819 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011820 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011821 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11822 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011823 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011824
11825 // Handle the processing of break.
11826 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827
11828 // Get the frame where the debugging is performed.
11829 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011830 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011832 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11833 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011834 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835
11836 // Traverse the saved contexts chain to find the active context for the
11837 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011838 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011840 SaveContext savex(isolate);
11841 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842
11843 // Create the (empty) function replacing the function on the stack frame for
11844 // the purpose of evaluating in the context created below. It is important
11845 // that this function does not describe any parameters and local variables
11846 // in the context. If it does then this will cause problems with the lookup
11847 // in Context::Lookup, where context slots for parameters and local variables
11848 // are looked at before the extension object.
11849 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11851 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852 go_between->set_context(function->context());
11853#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011854 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11855 ASSERT(go_between_scope_info->ParameterCount() == 0);
11856 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011857#endif
11858
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011859 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011860 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11861 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011862 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011863
11864 // Allocate a new context for the debug evaluation and set the extension
11865 // object build.
11866 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11868 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011869 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011870 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011871 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011872 Handle<Context> function_context;
11873 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011874 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011875 function_context = Handle<Context>(frame_context->declaration_context());
11876 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011877 context = CopyNestedScopeContextChain(isolate,
11878 go_between,
11879 context,
11880 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011881 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011882
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011883 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011884 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011885 context =
11886 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011887 }
11888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889 // Wrap the evaluation statement in a new function compiled in the newly
11890 // created context. The function has one parameter which has to be called
11891 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011892 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 isolate->factory()->NewStringFromAscii(
11897 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011898
11899 // Currently, the eval code will be executed in non-strict mode,
11900 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011901 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011902 Compiler::CompileEval(function_source,
11903 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011904 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011905 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011906 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011907 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011908 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011910
11911 // Invoke the result of the compilation to get the evaluation function.
11912 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011913 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011914 Handle<Object> evaluation_function =
11915 Execution::Call(compiled_function, receiver, 0, NULL,
11916 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011917 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011919 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011920 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011921 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011922 scope_info,
11923 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924
11925 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011926 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011927 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011928 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11929 receiver,
11930 ARRAY_SIZE(argv),
11931 argv,
11932 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011933 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011934
11935 // Skip the global proxy as it has no properties and always delegates to the
11936 // real global object.
11937 if (result->IsJSGlobalProxy()) {
11938 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11939 }
11940
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011941 return *result;
11942}
11943
11944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011945RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011946 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947
11948 // Check the execution state and decode arguments frame and source to be
11949 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011950 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011951 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011952 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11953 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011954 if (!maybe_check_result->ToObject(&check_result)) {
11955 return maybe_check_result;
11956 }
11957 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011958 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11959 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011960 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011961
11962 // Handle the processing of break.
11963 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011964
11965 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011967 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011968 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 top = top->prev();
11970 }
11971 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011972 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011973 }
11974
11975 // Get the global context now set to the top context from before the
11976 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011977 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011979 bool is_global = true;
11980
11981 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011982 // Create a new with context with the additional context information between
11983 // the context of the debugged function and the eval code to be executed.
11984 context = isolate->factory()->NewWithContext(
11985 Handle<JSFunction>(context->closure()),
11986 context,
11987 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011988 is_global = false;
11989 }
11990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011991 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011992 // Currently, the eval code will be executed in non-strict mode,
11993 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011994 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011995 Compiler::CompileEval(source,
11996 context,
11997 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011998 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011999 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012000 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012001 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 Handle<JSFunction>(
12003 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12004 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005
12006 // Invoke the result of the compilation to get the evaluation function.
12007 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012009 Handle<Object> result =
12010 Execution::Call(compiled_function, receiver, 0, NULL,
12011 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012012 // Clear the oneshot breakpoints so that the debugger does not step further.
12013 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012014 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015 return *result;
12016}
12017
12018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012019RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012020 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012021 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012023 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012024 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025
12026 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012027 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012028 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12029 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12030 // because using
12031 // instances->set(i, *GetScriptWrapper(script))
12032 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012033 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012034 Handle<JSValue> wrapper = GetScriptWrapper(script);
12035 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036 }
12037
12038 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012039 Handle<JSObject> result =
12040 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012041 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012042 return *result;
12043}
12044
12045
12046// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012047static int DebugReferencedBy(HeapIterator* iterator,
12048 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012049 Object* instance_filter, int max_references,
12050 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 JSFunction* arguments_function) {
12052 NoHandleAllocation ha;
12053 AssertNoAllocation no_alloc;
12054
12055 // Iterate the heap.
12056 int count = 0;
12057 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012058 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012059 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012060 (max_references == 0 || count < max_references)) {
12061 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062 if (heap_obj->IsJSObject()) {
12063 // Skip context extension objects and argument arrays as these are
12064 // checked in the context of functions using them.
12065 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012066 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012067 obj->map()->constructor() == arguments_function) {
12068 continue;
12069 }
12070
12071 // Check if the JS object has a reference to the object looked for.
12072 if (obj->ReferencesObject(target)) {
12073 // Check instance filter if supplied. This is normally used to avoid
12074 // references from mirror objects (see Runtime_IsInPrototypeChain).
12075 if (!instance_filter->IsUndefined()) {
12076 Object* V = obj;
12077 while (true) {
12078 Object* prototype = V->GetPrototype();
12079 if (prototype->IsNull()) {
12080 break;
12081 }
12082 if (instance_filter == prototype) {
12083 obj = NULL; // Don't add this object.
12084 break;
12085 }
12086 V = prototype;
12087 }
12088 }
12089
12090 if (obj != NULL) {
12091 // Valid reference found add to instance array if supplied an update
12092 // count.
12093 if (instances != NULL && count < instances_size) {
12094 instances->set(count, obj);
12095 }
12096 last = obj;
12097 count++;
12098 }
12099 }
12100 }
12101 }
12102
12103 // Check for circular reference only. This can happen when the object is only
12104 // referenced from mirrors and has a circular reference in which case the
12105 // object is not really alive and would have been garbage collected if not
12106 // referenced from the mirror.
12107 if (count == 1 && last == target) {
12108 count = 0;
12109 }
12110
12111 // Return the number of referencing objects found.
12112 return count;
12113}
12114
12115
12116// Scan the heap for objects with direct references to an object
12117// args[0]: the object to find references to
12118// args[1]: constructor function for instances to exclude (Mirror)
12119// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012120RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121 ASSERT(args.length() == 3);
12122
12123 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012124 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12125 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012126 // The heap iterator reserves the right to do a GC to make the heap iterable.
12127 // Due to the GC above we know it won't need to do that, but it seems cleaner
12128 // to get the heap iterator constructed before we start having unprotected
12129 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012130
12131 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012132 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012133 Object* instance_filter = args[1];
12134 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12135 instance_filter->IsJSObject());
12136 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12137 RUNTIME_ASSERT(max_references >= 0);
12138
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012142 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 JSFunction* arguments_function =
12144 JSFunction::cast(arguments_boilerplate->map()->constructor());
12145
12146 // Get the number of referencing objects.
12147 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012148 HeapIterator heap_iterator;
12149 count = DebugReferencedBy(&heap_iterator,
12150 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012151 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152
12153 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012154 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012155 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012156 if (!maybe_object->ToObject(&object)) return maybe_object;
12157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012158 FixedArray* instances = FixedArray::cast(object);
12159
12160 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012161 // AllocateFixedArray above does not make the heap non-iterable.
12162 ASSERT(HEAP->IsHeapIterable());
12163 HeapIterator heap_iterator2;
12164 count = DebugReferencedBy(&heap_iterator2,
12165 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012166 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012167
12168 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012169 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012170 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012171 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012172 if (!maybe_result->ToObject(&result)) return maybe_result;
12173 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174}
12175
12176
12177// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012178static int DebugConstructedBy(HeapIterator* iterator,
12179 JSFunction* constructor,
12180 int max_references,
12181 FixedArray* instances,
12182 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012183 AssertNoAllocation no_alloc;
12184
12185 // Iterate the heap.
12186 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012187 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012188 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012189 (max_references == 0 || count < max_references)) {
12190 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012191 if (heap_obj->IsJSObject()) {
12192 JSObject* obj = JSObject::cast(heap_obj);
12193 if (obj->map()->constructor() == constructor) {
12194 // Valid reference found add to instance array if supplied an update
12195 // count.
12196 if (instances != NULL && count < instances_size) {
12197 instances->set(count, obj);
12198 }
12199 count++;
12200 }
12201 }
12202 }
12203
12204 // Return the number of referencing objects found.
12205 return count;
12206}
12207
12208
12209// Scan the heap for objects constructed by a specific function.
12210// args[0]: the constructor to find instances of
12211// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012212RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 ASSERT(args.length() == 2);
12214
12215 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012216 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12217 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218
12219 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012220 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12222 RUNTIME_ASSERT(max_references >= 0);
12223
12224 // Get the number of referencing objects.
12225 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012226 HeapIterator heap_iterator;
12227 count = DebugConstructedBy(&heap_iterator,
12228 constructor,
12229 max_references,
12230 NULL,
12231 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232
12233 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012234 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012235 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012236 if (!maybe_object->ToObject(&object)) return maybe_object;
12237 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238 FixedArray* instances = FixedArray::cast(object);
12239
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012240 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012241 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012242 HeapIterator heap_iterator2;
12243 count = DebugConstructedBy(&heap_iterator2,
12244 constructor,
12245 max_references,
12246 instances,
12247 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248
12249 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012250 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012251 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12252 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012253 if (!maybe_result->ToObject(&result)) return maybe_result;
12254 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012255 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012256}
12257
12258
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012259// Find the effective prototype object as returned by __proto__.
12260// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012261RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 ASSERT(args.length() == 1);
12263
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012264 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012265
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012266 // Use the __proto__ accessor.
12267 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268}
12269
12270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012271RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012272 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012273 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012274 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012275}
12276
12277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012278RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012279#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012280 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012281 ASSERT(args.length() == 1);
12282 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012283 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012284 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012285 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012286 return Failure::Exception();
12287 }
12288 func->code()->PrintLn();
12289#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012290 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012291}
ager@chromium.org9085a012009-05-11 19:22:57 +000012292
12293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012294RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012295#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012296 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012297 ASSERT(args.length() == 1);
12298 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012299 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012300 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012301 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012302 return Failure::Exception();
12303 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012304 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012305#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012306 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012307}
12308
12309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012310RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012311 NoHandleAllocation ha;
12312 ASSERT(args.length() == 1);
12313
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012314 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012315 return f->shared()->inferred_name();
12316}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012317
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012318
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012319static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12320 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012321 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012322 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012323 int counter = 0;
12324 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012325 for (HeapObject* obj = iterator->next();
12326 obj != NULL;
12327 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012328 ASSERT(obj != NULL);
12329 if (!obj->IsSharedFunctionInfo()) {
12330 continue;
12331 }
12332 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12333 if (shared->script() != script) {
12334 continue;
12335 }
12336 if (counter < buffer_size) {
12337 buffer->set(counter, shared);
12338 }
12339 counter++;
12340 }
12341 return counter;
12342}
12343
12344// For a script finds all SharedFunctionInfo's in the heap that points
12345// to this script. Returns JSArray of SharedFunctionInfo wrapped
12346// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012347RUNTIME_FUNCTION(MaybeObject*,
12348 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012349 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012350 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012351 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012352
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012353
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012354 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12355
12356 const int kBufferSize = 32;
12357
12358 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012359 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012360 int number;
12361 {
12362 isolate->heap()->EnsureHeapIsIterable();
12363 AssertNoAllocation no_allocations;
12364 HeapIterator heap_iterator;
12365 Script* scr = *script;
12366 FixedArray* arr = *array;
12367 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12368 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012369 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012370 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012371 isolate->heap()->EnsureHeapIsIterable();
12372 AssertNoAllocation no_allocations;
12373 HeapIterator heap_iterator;
12374 Script* scr = *script;
12375 FixedArray* arr = *array;
12376 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012377 }
12378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012380 result->set_length(Smi::FromInt(number));
12381
12382 LiveEdit::WrapSharedFunctionInfos(result);
12383
12384 return *result;
12385}
12386
12387// For a script calculates compilation information about all its functions.
12388// The script source is explicitly specified by the second argument.
12389// The source of the actual script is not used, however it is important that
12390// all generated code keeps references to this particular instance of script.
12391// Returns a JSArray of compilation infos. The array is ordered so that
12392// each function with all its descendant is always stored in a continues range
12393// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012394RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012395 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012396 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012397 CONVERT_ARG_CHECKED(JSValue, script, 0);
12398 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012399 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12400
12401 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012403 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012404 return Failure::Exception();
12405 }
12406
12407 return result;
12408}
12409
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012410// Changes the source of the script to a new_source.
12411// If old_script_name is provided (i.e. is a String), also creates a copy of
12412// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012413RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012414 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012415 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012416 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12417 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012418 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012419
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012420 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12421 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012422
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012423 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12424 new_source,
12425 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012426
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012427 if (old_script->IsScript()) {
12428 Handle<Script> script_handle(Script::cast(old_script));
12429 return *(GetScriptWrapper(script_handle));
12430 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012432 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012433}
12434
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012436RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012437 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012439 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012440 return LiveEdit::FunctionSourceUpdated(shared_info);
12441}
12442
12443
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012444// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012445RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012446 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012447 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012448 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12449 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012450
ager@chromium.orgac091b72010-05-05 07:34:42 +000012451 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012452}
12453
12454// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012455RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012456 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012457 HandleScope scope(isolate);
12458 Handle<Object> function_object(args[0], isolate);
12459 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012460
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012461 if (function_object->IsJSValue()) {
12462 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12463 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012464 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12465 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012467 }
12468
12469 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12470 } else {
12471 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12472 // and we check it in this function.
12473 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012475 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012476}
12477
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012478
12479// In a code of a parent function replaces original function as embedded object
12480// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012481RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012482 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012483 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012484
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012485 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12486 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12487 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012488
12489 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12490 subst_wrapper);
12491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012492 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012493}
12494
12495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012496// Updates positions of a shared function info (first parameter) according
12497// to script source change. Text change is described in second parameter as
12498// array of groups of 3 numbers:
12499// (change_begin, change_end, change_end_new_position).
12500// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012501RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012502 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012503 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012504 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12505 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012506
ager@chromium.orgac091b72010-05-05 07:34:42 +000012507 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012508}
12509
12510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012511// For array of SharedFunctionInfo's (each wrapped in JSValue)
12512// checks that none of them have activations on stacks (of any thread).
12513// Returns array of the same length with corresponding results of
12514// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012515RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012516 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012517 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012518 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12519 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012520
ager@chromium.org357bf652010-04-12 11:30:10 +000012521 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012522}
12523
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012524// Compares 2 strings line-by-line, then token-wise and returns diff in form
12525// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12526// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012527RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012528 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012529 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012530 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12531 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012532
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012533 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012534}
12535
12536
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012537// A testing entry. Returns statement position which is the closest to
12538// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012539RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012540 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012541 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012542 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012543 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12544
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012545 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012546
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012547 if (code->kind() != Code::FUNCTION &&
12548 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012550 }
12551
12552 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012553 int closest_pc = 0;
12554 int distance = kMaxInt;
12555 while (!it.done()) {
12556 int statement_position = static_cast<int>(it.rinfo()->data());
12557 // Check if this break point is closer that what was previously found.
12558 if (source_position <= statement_position &&
12559 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012560 closest_pc =
12561 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012562 distance = statement_position - source_position;
12563 // Check whether we can't get any closer.
12564 if (distance == 0) break;
12565 }
12566 it.next();
12567 }
12568
12569 return Smi::FromInt(closest_pc);
12570}
12571
12572
ager@chromium.org357bf652010-04-12 11:30:10 +000012573// Calls specified function with or without entering the debugger.
12574// This is used in unit tests to run code as if debugger is entered or simply
12575// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012576RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012577 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012579 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12580 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012581
12582 Handle<Object> result;
12583 bool pending_exception;
12584 {
12585 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012586 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012587 &pending_exception);
12588 } else {
12589 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012590 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012591 &pending_exception);
12592 }
12593 }
12594 if (!pending_exception) {
12595 return *result;
12596 } else {
12597 return Failure::Exception();
12598 }
12599}
12600
12601
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012602// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012603RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012604 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012605 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012606 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12607 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012608 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012609}
12610
12611
12612// Performs a GC.
12613// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012614RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012615 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012616 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012617}
12618
12619
12620// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012621RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012622 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012623 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012624 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012625 }
12626 return Smi::FromInt(usage);
12627}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012628
12629
12630// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012631RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012632#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012633 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012634#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012635 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012636#endif
12637}
12638
12639
12640// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012641RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012642#ifdef LIVE_OBJECT_LIST
12643 return LiveObjectList::Capture();
12644#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012646#endif
12647}
12648
12649
12650// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012651RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012652#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012653 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012654 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012655 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012656#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012658#endif
12659}
12660
12661
12662// Generates the response to a debugger request for a dump of the objects
12663// contained in the difference between the captured live object lists
12664// specified by id1 and id2.
12665// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12666// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012667RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012668#ifdef LIVE_OBJECT_LIST
12669 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012670 CONVERT_SMI_ARG_CHECKED(id1, 0);
12671 CONVERT_SMI_ARG_CHECKED(id2, 1);
12672 CONVERT_SMI_ARG_CHECKED(start, 2);
12673 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012674 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012675 EnterDebugger enter_debugger;
12676 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12677#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012678 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012679#endif
12680}
12681
12682
12683// Gets the specified object as requested by the debugger.
12684// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012686#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012687 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012688 Object* result = LiveObjectList::GetObj(obj_id);
12689 return result;
12690#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012691 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012692#endif
12693}
12694
12695
12696// Gets the obj id for the specified address if valid.
12697// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012698RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012699#ifdef LIVE_OBJECT_LIST
12700 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012701 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012702 Object* result = LiveObjectList::GetObjId(address);
12703 return result;
12704#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012705 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012706#endif
12707}
12708
12709
12710// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012711RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012712#ifdef LIVE_OBJECT_LIST
12713 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012714 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012715 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12716 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12717 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12718 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012719 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012720
12721 Handle<JSObject> instance_filter;
12722 if (args[1]->IsJSObject()) {
12723 instance_filter = args.at<JSObject>(1);
12724 }
12725 bool verbose = false;
12726 if (args[2]->IsBoolean()) {
12727 verbose = args[2]->IsTrue();
12728 }
12729 int start = 0;
12730 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012731 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012732 }
12733 int limit = Smi::kMaxValue;
12734 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012735 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012736 }
12737
12738 return LiveObjectList::GetObjRetainers(obj_id,
12739 instance_filter,
12740 verbose,
12741 start,
12742 limit,
12743 filter_obj);
12744#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012745 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012746#endif
12747}
12748
12749
12750// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012751RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012752#ifdef LIVE_OBJECT_LIST
12753 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012754 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12755 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012756 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12757
12758 Handle<JSObject> instance_filter;
12759 if (args[2]->IsJSObject()) {
12760 instance_filter = args.at<JSObject>(2);
12761 }
12762
12763 Object* result =
12764 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12765 return result;
12766#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012767 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012768#endif
12769}
12770
12771
12772// Generates the response to a debugger request for a list of all
12773// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012774RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012775#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012776 CONVERT_SMI_ARG_CHECKED(start, 0);
12777 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012778 return LiveObjectList::Info(start, count);
12779#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012780 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012781#endif
12782}
12783
12784
12785// Gets a dump of the specified object as requested by the debugger.
12786// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012787RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012788#ifdef LIVE_OBJECT_LIST
12789 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012790 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012791 Object* result = LiveObjectList::PrintObj(obj_id);
12792 return result;
12793#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012794 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012795#endif
12796}
12797
12798
12799// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012800RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012801#ifdef LIVE_OBJECT_LIST
12802 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012803 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012804#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012805 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012806#endif
12807}
12808
12809
12810// Generates the response to a debugger request for a summary of the types
12811// of objects in the difference between the captured live object lists
12812// specified by id1 and id2.
12813// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12814// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012815RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012816#ifdef LIVE_OBJECT_LIST
12817 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012818 CONVERT_SMI_ARG_CHECKED(id1, 0);
12819 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012820 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012821
12822 EnterDebugger enter_debugger;
12823 return LiveObjectList::Summarize(id1, id2, filter_obj);
12824#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012826#endif
12827}
12828
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012829#endif // ENABLE_DEBUGGER_SUPPORT
12830
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012832RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012833 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012834 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012835 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012836}
12837
12838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012839RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012840 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012841 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012843}
12844
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012845
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012846// Finds the script object from the script data. NOTE: This operation uses
12847// heap traversal to find the function generated for the source position
12848// for the requested break point. For lazily compiled functions several heap
12849// traversals might be required rendering this operation as a rather slow
12850// operation. However for setting break points which is normally done through
12851// some kind of user interaction the performance is not crucial.
12852static Handle<Object> Runtime_GetScriptFromScriptName(
12853 Handle<String> script_name) {
12854 // Scan the heap for Script objects to find the script with the requested
12855 // script data.
12856 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012857 script_name->GetHeap()->EnsureHeapIsIterable();
12858 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012859 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012860 HeapObject* obj = NULL;
12861 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012862 // If a script is found check if it has the script data requested.
12863 if (obj->IsScript()) {
12864 if (Script::cast(obj)->name()->IsString()) {
12865 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12866 script = Handle<Script>(Script::cast(obj));
12867 }
12868 }
12869 }
12870 }
12871
12872 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012873 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012874
12875 // Return the script found.
12876 return GetScriptWrapper(script);
12877}
12878
12879
12880// Get the script object from script data. NOTE: Regarding performance
12881// see the NOTE for GetScriptFromScriptData.
12882// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012883RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012885
12886 ASSERT(args.length() == 1);
12887
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012888 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012889
12890 // Find the requested script.
12891 Handle<Object> result =
12892 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12893 return *result;
12894}
12895
12896
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012897// Determines whether the given stack frame should be displayed in
12898// a stack trace. The caller is the error constructor that asked
12899// for the stack trace to be collected. The first time a construct
12900// call to this function is encountered it is skipped. The seen_caller
12901// in/out parameter is used to remember if the caller has been seen
12902// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012903static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12904 Object* caller,
12905 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012906 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012907 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012908 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012909 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012910 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12911 Object* raw_fun = frame->function();
12912 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012913 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012914 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012915 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012916 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012917 *seen_caller = true;
12918 return false;
12919 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012920 // Skip all frames until we've seen the caller.
12921 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012922 // Also, skip non-visible built-in functions and any call with the builtins
12923 // object as receiver, so as to not reveal either the builtins object or
12924 // an internal function.
12925 // The --builtins-in-stack-traces command line flag allows including
12926 // internal call sites in the stack trace for debugging purposes.
12927 if (!FLAG_builtins_in_stack_traces) {
12928 JSFunction* fun = JSFunction::cast(raw_fun);
12929 if (frame->receiver()->IsJSBuiltinsObject() ||
12930 (fun->IsBuiltin() && !fun->shared()->native())) {
12931 return false;
12932 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012933 }
12934 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012935}
12936
12937
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012938// Collect the raw data for a stack trace. Returns an array of 4
12939// element segments each containing a receiver, function, code and
12940// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012941RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012942 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012943 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012944 Handle<Object> caller = args.at<Object>(1);
12945 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012947 HandleScope scope(isolate);
12948 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012949
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012950 limit = Max(limit, 0); // Ensure that limit is not negative.
12951 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012952 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012953 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012954
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012955 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012956 // If the caller parameter is a function we skip frames until we're
12957 // under it before starting to collect.
12958 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012959 int cursor = 0;
12960 int frames_seen = 0;
12961 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012962 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012963 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012964 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012965 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012966 // Set initial size to the maximum inlining level + 1 for the outermost
12967 // function.
12968 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012969 frame->Summarize(&frames);
12970 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012971 if (cursor + 4 > elements->length()) {
12972 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12973 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012974 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012975 for (int i = 0; i < cursor; i++) {
12976 new_elements->set(i, elements->get(i));
12977 }
12978 elements = new_elements;
12979 }
12980 ASSERT(cursor + 4 <= elements->length());
12981
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012982 Handle<Object> recv = frames[i].receiver();
12983 Handle<JSFunction> fun = frames[i].function();
12984 Handle<Code> code = frames[i].code();
12985 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012986 elements->set(cursor++, *recv);
12987 elements->set(cursor++, *fun);
12988 elements->set(cursor++, *code);
12989 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012990 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012991 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012992 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012993 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012994 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012995 // Capture and attach a more detailed stack trace if necessary.
12996 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012997 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012998 return *result;
12999}
13000
13001
ager@chromium.org3811b432009-10-28 14:53:37 +000013002// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013003RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013004 ASSERT_EQ(args.length(), 0);
13005
13006 NoHandleAllocation ha;
13007
13008 const char* version_string = v8::V8::GetVersion();
13009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013010 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13011 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013012}
13013
13014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013015RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013016 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013017 OS::PrintError("abort: %s\n",
13018 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013020 OS::Abort();
13021 UNREACHABLE();
13022 return NULL;
13023}
13024
13025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013026RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013027 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013028 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013029 Object* key = args[1];
13030
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013031 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013032 Object* o = cache->get(finger_index);
13033 if (o == key) {
13034 // The fastest case: hit the same place again.
13035 return cache->get(finger_index + 1);
13036 }
13037
13038 for (int i = finger_index - 2;
13039 i >= JSFunctionResultCache::kEntriesIndex;
13040 i -= 2) {
13041 o = cache->get(i);
13042 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013043 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013044 return cache->get(i + 1);
13045 }
13046 }
13047
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013048 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013049 ASSERT(size <= cache->length());
13050
13051 for (int i = size - 2; i > finger_index; i -= 2) {
13052 o = cache->get(i);
13053 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013054 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013055 return cache->get(i + 1);
13056 }
13057 }
13058
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013059 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013060 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013061
13062 Handle<JSFunctionResultCache> cache_handle(cache);
13063 Handle<Object> key_handle(key);
13064 Handle<Object> value;
13065 {
13066 Handle<JSFunction> factory(JSFunction::cast(
13067 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13068 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013070 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013071 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013072 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013073 value = Execution::Call(factory,
13074 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013075 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013076 argv,
13077 &pending_exception);
13078 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013079 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013080
13081#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013082 if (FLAG_verify_heap) {
13083 cache_handle->JSFunctionResultCacheVerify();
13084 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013085#endif
13086
13087 // Function invocation may have cleared the cache. Reread all the data.
13088 finger_index = cache_handle->finger_index();
13089 size = cache_handle->size();
13090
13091 // If we have spare room, put new data into it, otherwise evict post finger
13092 // entry which is likely to be the least recently used.
13093 int index = -1;
13094 if (size < cache_handle->length()) {
13095 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13096 index = size;
13097 } else {
13098 index = finger_index + JSFunctionResultCache::kEntrySize;
13099 if (index == cache_handle->length()) {
13100 index = JSFunctionResultCache::kEntriesIndex;
13101 }
13102 }
13103
13104 ASSERT(index % 2 == 0);
13105 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13106 ASSERT(index < cache_handle->length());
13107
13108 cache_handle->set(index, *key_handle);
13109 cache_handle->set(index + 1, *value);
13110 cache_handle->set_finger_index(index);
13111
13112#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013113 if (FLAG_verify_heap) {
13114 cache_handle->JSFunctionResultCacheVerify();
13115 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013116#endif
13117
13118 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013119}
13120
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013122RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013123 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013124 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13125 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013126 return *isolate->factory()->NewJSMessageObject(
13127 type,
13128 arguments,
13129 0,
13130 0,
13131 isolate->factory()->undefined_value(),
13132 isolate->factory()->undefined_value(),
13133 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013134}
13135
13136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013137RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013138 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013139 return message->type();
13140}
13141
13142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013143RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013144 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013145 return message->arguments();
13146}
13147
13148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013149RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013150 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013151 return Smi::FromInt(message->start_position());
13152}
13153
13154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013155RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013156 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013157 return message->script();
13158}
13159
13160
kasper.lund44510672008-07-25 07:37:58 +000013161#ifdef DEBUG
13162// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13163// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013164RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013165 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013166 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013167#define COUNT_ENTRY(Name, argc, ressize) + 1
13168 int entry_count = 0
13169 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13170 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13171 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13172#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013173 Factory* factory = isolate->factory();
13174 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013175 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013176 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013177#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013178 { \
13179 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013180 Handle<String> name; \
13181 /* Inline runtime functions have an underscore in front of the name. */ \
13182 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013183 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013184 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13185 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013186 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013187 Vector<const char>(#Name, StrLength(#Name))); \
13188 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013189 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013190 pair_elements->set(0, *name); \
13191 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013192 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013193 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013194 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013195 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013196 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013197 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013198 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013199 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013200#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013201 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013202 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013203 return *result;
13204}
kasper.lund44510672008-07-25 07:37:58 +000013205#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013206
13207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013208RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013209 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013210 CONVERT_ARG_CHECKED(String, format, 0);
13211 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013212 String::FlatContent format_content = format->GetFlatContent();
13213 RUNTIME_ASSERT(format_content.IsAscii());
13214 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013215 LOGGER->LogRuntime(chars, elms);
13216 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013217}
13218
13219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013220RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013221 UNREACHABLE(); // implemented as macro in the parser
13222 return NULL;
13223}
13224
13225
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013226#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13227 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013228 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013229 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13230 }
13231
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013232ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013233ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13234ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13235ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13236ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13237ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13238ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13239ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13240ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13241ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13242ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13243ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13244ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13245ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13246
13247#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13248
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013249
13250RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13251 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013252 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13253 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013254 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13255}
13256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013257// ----------------------------------------------------------------------------
13258// Implementation of Runtime
13259
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013260#define F(name, number_of_args, result_size) \
13261 { Runtime::k##name, Runtime::RUNTIME, #name, \
13262 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013263
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013264
13265#define I(name, number_of_args, result_size) \
13266 { Runtime::kInline##name, Runtime::INLINE, \
13267 "_" #name, NULL, number_of_args, result_size },
13268
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013269static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013270 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013271 INLINE_FUNCTION_LIST(I)
13272 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013273};
13274
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013276MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13277 Object* dictionary) {
13278 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013279 ASSERT(dictionary != NULL);
13280 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13281 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013282 Object* name_symbol;
13283 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013284 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013285 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13286 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013287 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013288 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13289 String::cast(name_symbol),
13290 Smi::FromInt(i),
13291 PropertyDetails(NONE, NORMAL));
13292 if (!maybe_dictionary->ToObject(&dictionary)) {
13293 // Non-recoverable failure. Calling code must restart heap
13294 // initialization.
13295 return maybe_dictionary;
13296 }
13297 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013298 }
13299 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013300}
13301
13302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013303const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13304 Heap* heap = name->GetHeap();
13305 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013306 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013307 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013308 int function_index = Smi::cast(smi_index)->value();
13309 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013310 }
13311 return NULL;
13312}
13313
13314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013315const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013316 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13317}
13318
13319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013320void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013321 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013322 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013323 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013324 if (isolate->heap()->new_space()->AddFreshPage()) {
13325 return;
13326 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013327 // Try to do a garbage collection; ignore it if it fails. The C
13328 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013329 isolate->heap()->CollectGarbage(failure->allocation_space(),
13330 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013331 } else {
13332 // Handle last resort GC and make sure to allow future allocations
13333 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013334 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013335 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13336 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013338}
13339
13340
13341} } // namespace v8::internal