blob: 6e93e58620d04564d04255dcef9571b17540b104 [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
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1341
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001349 if (is_function_declaration) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001351 // Do not overwrite READ_ONLY properties.
1352 if (lookup.GetAttributes() & READ_ONLY) {
1353 if (language_mode != CLASSIC_MODE) {
1354 Handle<Object> args[] = { name };
1355 return isolate->Throw(*isolate->factory()->NewTypeError(
1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
1357 }
1358 continue;
1359 }
1360 // Do not change DONT_DELETE to false from true.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001361 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1364
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001365 RETURN_IF_EMPTY_HANDLE(
1366 isolate,
1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1368 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001370 RETURN_IF_EMPTY_HANDLE(
1371 isolate,
1372 JSReceiver::SetProperty(global, name, value,
1373 static_cast<PropertyAttributes>(attr),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001374 language_mode == CLASSIC_MODE
1375 ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 }
1377 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 ASSERT(!isolate->has_pending_exception());
1380 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381}
1382
1383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001384RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001385 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001386 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001388 // Declarations are always made in a function or global context. In the
1389 // case of eval code, the context passed is the context of the caller,
1390 // which may be some nested context and not the declaration context.
1391 RUNTIME_ASSERT(args[0]->IsContext());
1392 Handle<Context> context(Context::cast(args[0])->declaration_context());
1393
ager@chromium.org7c537e22008-10-16 08:43:32 +00001394 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001395 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001396 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 int index;
1400 PropertyAttributes attributes;
1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001402 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001403 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001404 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405
1406 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1409 // Functions are not read-only.
1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
1415 // Initialize it if necessary.
1416 if (*initial_value != NULL) {
1417 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 ASSERT(holder.is_identical_to(context));
1419 if (((attributes & READ_ONLY) == 0) ||
1420 context->get(index)->IsTheHole()) {
1421 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Slow case: The property is in the context extension object of a
1425 // function context or the global object of a global context.
1426 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001427 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001429 JSReceiver::SetProperty(object, name, initial_value, mode,
1430 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 }
1432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001435 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 // "declared" in the function context's extension context or as a
1437 // property of the the global object.
1438 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001439 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 // Context extension objects are allocated lazily.
1443 ASSERT(context->IsFunctionContext());
1444 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001447 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449
ager@chromium.org7c537e22008-10-16 08:43:32 +00001450 // Declare the property by setting it to the initial value if provided,
1451 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1452 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001453 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001455 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001456 // Declaring a const context slot is a conflicting declaration if
1457 // there is a callback with that name in a prototype. It is
1458 // allowed to introduce const variables in
1459 // JSContextExtensionObjects. They are treated specially in
1460 // SetProperty and no setters are invoked for those since they are
1461 // not real JSObjects.
1462 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001464 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001468 }
1469 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001470 RETURN_IF_EMPTY_HANDLE(
1471 isolate,
1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001473 }
1474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001481 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001482 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
1485 // Determine if we need to assign to the variable if it already
1486 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1488 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001492 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1495 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496
1497 // According to ECMA-262, section 12.2, page 62, the property must
1498 // not be deletable.
1499 PropertyAttributes attributes = DONT_DELETE;
1500
1501 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001502 // there, there is a property with this name in the prototype chain.
1503 // We follow Safari and Firefox behavior and only set the property
1504 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001505 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001506 // Note that objects can have hidden prototypes, so we need to traverse
1507 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001509 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 while (object->IsJSObject() &&
1511 JSObject::cast(object)->map()->is_hidden_prototype()) {
1512 JSObject* raw_holder = JSObject::cast(object);
1513 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001514 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 HandleScope handle_scope(isolate);
1516 Handle<JSObject> holder(raw_holder);
1517 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1518 // Update the raw pointer in case it's changed due to GC.
1519 raw_holder = *holder;
1520 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1521 // Found an interceptor that's not read only.
1522 if (assign) {
1523 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001524 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 } else {
1526 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001527 }
1528 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001529 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 }
1532
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001535 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001536 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001537 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001538 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539}
1540
1541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001542RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // All constants are declared with an initial value. The name
1544 // of the constant is the first argument and the initial value
1545 // is the second.
1546 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001547 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 Handle<Object> value = args.at<Object>(1);
1549
1550 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001551 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
1553 // According to ECMA-262, section 12.2, page 62, the property must
1554 // not be deletable. Since it's a const, it must be READ_ONLY too.
1555 PropertyAttributes attributes =
1556 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1557
1558 // Lookup the property locally in the global object. If it isn't
1559 // there, we add the property and take special precautions to always
1560 // add it as a local property even in case of callbacks in the
1561 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001562 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001563 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 global->LocalLookup(*name, &lookup);
1565 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001566 return global->SetLocalPropertyIgnoreAttributes(*name,
1567 *value,
1568 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 }
1570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001574 HandleScope handle_scope(isolate);
1575 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001577 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 // property through an interceptor and only do it if it's
1579 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001580 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001581 RETURN_IF_EMPTY_HANDLE(
1582 isolate,
1583 JSReceiver::SetProperty(global, name, value, attributes,
1584 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 return *value;
1586 }
1587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 // constant. For now, we determine this by checking if the
1590 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = global->properties();
1595 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001600 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1601 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001602 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 }
1604 } else {
1605 // Ignore re-initialization of constants that have already been
1606 // assigned a function value.
1607 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1608 }
1609
1610 // Use the set value as the result of the operation.
1611 return *value;
1612}
1613
1614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001615RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 ASSERT(args.length() == 3);
1618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001619 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001622 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 RUNTIME_ASSERT(args[1]->IsContext());
1624 Handle<Context> context(Context::cast(args[1])->declaration_context());
1625
1626 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627
1628 int index;
1629 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001631 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001632 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001633 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 ASSERT(holder->IsContext());
1637 // Property was found in a context. Perform the assignment if we
1638 // found some non-constant or an uninitialized constant.
1639 Handle<Context> context = Handle<Context>::cast(holder);
1640 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1641 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 }
1643 return *value;
1644 }
1645
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001646 // The property could not be found, we introduce it as a property of the
1647 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 Handle<JSObject> global = Handle<JSObject>(
1650 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001651 // Strict mode not needed (const disallowed in strict mode).
1652 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001654 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 return *value;
1656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 // The property was present in some function's context extension object,
1659 // as a property on the subject of a with, or as a property of the global
1660 // object.
1661 //
1662 // In most situations, eval-introduced consts should still be present in
1663 // the context extension object. However, because declaration and
1664 // initialization are separate, the property might have been deleted
1665 // before we reach the initialization point.
1666 //
1667 // Example:
1668 //
1669 // function f() { eval("delete x; const x;"); }
1670 //
1671 // In that case, the initialization behaves like a normal assignment.
1672 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 if (*object == context->extension()) {
1675 // This is the property that was introduced by the const declaration.
1676 // Set it if it hasn't been set before. NOTE: We cannot use
1677 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001678 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001679 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001680 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1682
1683 PropertyType type = lookup.type();
1684 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001685 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 int index = lookup.GetFieldIndex();
1687 if (properties->get(index)->IsTheHole()) {
1688 properties->set(index, *value);
1689 }
1690 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1692 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 }
1694 } else {
1695 // We should not reach here. Any real, named property should be
1696 // either a field or a dictionary slot.
1697 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 }
1699 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 // The property was found on some other object. Set it if it is not a
1701 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001702 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001704 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001706 JSReceiver::SetProperty(object, name, value, attributes,
1707 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 return *value;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*,
1716 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001718 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001720 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001721 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001723 }
1724 return *object;
1725}
1726
1727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001728RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001733 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001737 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001738 RUNTIME_ASSERT(index >= 0);
1739 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001741 Handle<Object> result = RegExpImpl::Exec(regexp,
1742 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001743 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001744 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001745 if (result.is_null()) return Failure::Exception();
1746 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001747}
1748
1749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001750RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001751 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001752 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001753 if (elements_count < 0 ||
1754 elements_count > FixedArray::kMaxLength ||
1755 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001758 Object* new_object;
1759 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1762 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001763 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1765 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1767 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001768 {
1769 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001771 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001773 }
1774 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001776 array->set_elements(elements);
1777 array->set_length(Smi::FromInt(elements_count));
1778 // Write in-object properties after the length of the array.
1779 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1780 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1781 return array;
1782}
1783
1784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001785RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786 AssertNoAllocation no_alloc;
1787 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001788 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1789 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001793
1794 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001796
1797 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799
1800 Map* map = regexp->map();
1801 Object* constructor = map->constructor();
1802 if (constructor->IsJSFunction() &&
1803 JSFunction::cast(constructor)->initial_map() == map) {
1804 // If we still have the original map, set in-object properties directly.
1805 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001806 // Both true and false are immovable immortal objects so no need for write
1807 // barrier.
1808 regexp->InObjectPropertyAtPut(
1809 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1810 regexp->InObjectPropertyAtPut(
1811 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1812 regexp->InObjectPropertyAtPut(
1813 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1815 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001816 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001817 return regexp;
1818 }
1819
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 PropertyAttributes final =
1822 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1823 PropertyAttributes writable =
1824 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001825 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 source,
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->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 global,
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->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 ignoreCase,
1838 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001841 multiline,
1842 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001843 ASSERT(!result->IsFailure());
1844 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001845 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001846 Smi::FromInt(0),
1847 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848 ASSERT(!result->IsFailure());
1849 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001850 return regexp;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001856 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001857 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001858 // This is necessary to enable fast checks for absence of elements
1859 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001861 return Smi::FromInt(0);
1862}
1863
1864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1866 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001868 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001869 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1870 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1871 Handle<JSFunction> optimized =
1872 isolate->factory()->NewFunction(key,
1873 JS_OBJECT_TYPE,
1874 JSObject::kHeaderSize,
1875 code,
1876 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001877 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001878 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001879 return optimized;
1880}
1881
1882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001886 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001887
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001888 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1889 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1890 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1891 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1892 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1893 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1894 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001895
1896 return *holder;
1897}
1898
1899
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001901 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001902 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001903
1904 if (!callable->IsJSFunction()) {
1905 HandleScope scope(isolate);
1906 bool threw = false;
1907 Handle<Object> delegate =
1908 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1909 if (threw) return Failure::Exception();
1910 callable = JSFunction::cast(*delegate);
1911 }
1912 JSFunction* function = JSFunction::cast(callable);
1913
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001914 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001915 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001916 return isolate->heap()->undefined_value();
1917 }
1918 // Returns undefined for strict or native functions, or
1919 // the associated global receiver for "normal" functions.
1920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001922 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001923 return global_context->global()->global_receiver();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001928 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001930 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001931 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 Handle<String> pattern = args.at<String>(2);
1933 Handle<String> flags = args.at<String>(3);
1934
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001935 // Get the RegExp function from the context in the literals array.
1936 // This is the RegExp function from the context in which the
1937 // function was created. We do not use the RegExp function from the
1938 // current global context because this might be the RegExp function
1939 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001940 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001941 Handle<JSFunction>(
1942 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 // Compute the regular expression literal.
1944 bool has_pending_exception;
1945 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1947 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 return Failure::Exception();
1951 }
1952 literals->set(index, *regexp);
1953 return *regexp;
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return f->shared()->name();
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 2);
1969
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001970 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1971 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001972 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001974}
1975
1976
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
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 return isolate->heap()->ToBoolean(
1982 f->shared()->name_should_print_as_anonymous());
1983}
1984
1985
1986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001989 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001990 f->shared()->set_name_should_print_as_anonymous(true);
1991 return isolate->heap()->undefined_value();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001999 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 Object* obj = f->RemovePrototype();
2001 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002004}
2005
2006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 ASSERT(args.length() == 1);
2010
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002011 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2013 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014
2015 return *GetScriptWrapper(Handle<Script>::cast(script));
2016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002020 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 ASSERT(args.length() == 1);
2022
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002024 Handle<SharedFunctionInfo> shared(f->shared());
2025 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 1);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 int pos = fun->shared()->start_position();
2035 return Smi::FromInt(pos);
2036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040 ASSERT(args.length() == 2);
2041
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002042 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002043 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2044
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2046
2047 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002049}
2050
2051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002052RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 NoHandleAllocation ha;
2054 ASSERT(args.length() == 2);
2055
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002056 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2057 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060}
2061
2062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 NoHandleAllocation ha;
2065 ASSERT(args.length() == 2);
2066
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002067 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2068 CONVERT_SMI_ARG_CHECKED(length, 1);
2069 fun->shared()->set_length(length);
2070 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071}
2072
2073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002075 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 ASSERT(args.length() == 2);
2077
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002078 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002079 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002080 Object* obj;
2081 { MaybeObject* maybe_obj =
2082 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2083 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 return args[0]; // return TOS
2086}
2087
2088
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2090 NoHandleAllocation ha;
2091 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002092 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002093
2094 MaybeObject* maybe_name =
2095 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2096 String* name;
2097 if (!maybe_name->To(&name)) return maybe_name;
2098
2099 if (function->HasFastProperties()) {
2100 // Construct a new field descriptor with updated attributes.
2101 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2102 int index = instance_desc->Search(name);
2103 ASSERT(index != DescriptorArray::kNotFound);
2104 PropertyDetails details(instance_desc->GetDetails(index));
2105 CallbacksDescriptor new_desc(name,
2106 instance_desc->GetValue(index),
2107 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2108 details.index());
2109 // Construct a new field descriptors array containing the new descriptor.
2110 Object* descriptors_unchecked;
2111 { MaybeObject* maybe_descriptors_unchecked =
2112 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2113 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2114 return maybe_descriptors_unchecked;
2115 }
2116 }
2117 DescriptorArray* new_descriptors =
2118 DescriptorArray::cast(descriptors_unchecked);
2119 // Create a new map featuring the new field descriptors array.
2120 Object* map_unchecked;
2121 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2122 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2123 return maybe_map_unchecked;
2124 }
2125 }
2126 Map* new_map = Map::cast(map_unchecked);
2127 new_map->set_instance_descriptors(new_descriptors);
2128 function->set_map(new_map);
2129 } else { // Dictionary properties.
2130 // Directly manipulate the property details.
2131 int entry = function->property_dictionary()->FindEntry(name);
2132 ASSERT(entry != StringDictionary::kNotFound);
2133 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2134 PropertyDetails new_details(
2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2136 details.type(),
2137 details.index());
2138 function->property_dictionary()->DetailsAtPut(entry, new_details);
2139 }
2140 return function;
2141}
2142
2143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +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->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002150}
2151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002154 NoHandleAllocation ha;
2155 ASSERT(args.length() == 1);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002158 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002159}
2160
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002162RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 ASSERT(args.length() == 2);
2165
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002166 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 Handle<Object> code = args.at<Object>(1);
2168
2169 Handle<Context> context(target->context());
2170
2171 if (!code->IsNull()) {
2172 RUNTIME_ASSERT(code->IsJSFunction());
2173 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002176 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 return Failure::Exception();
2178 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002179 // Since we don't store the source for this we should never
2180 // optimize this.
2181 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 // Set the code, scope info, formal parameter count,
2183 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002184 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002185 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002186 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002187 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002189 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002190 // Set the source code of the target function to undefined.
2191 // SetCode is only used for built-in constructors like String,
2192 // Array, and Object, and some web code
2193 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002195 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002196 // Clear the optimization hints related to the compiled code as these are no
2197 // longer valid when the code is overwritten.
2198 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 context = Handle<Context>(fun->context());
2200
2201 // Make sure we get a fresh copy of the literal vector to avoid
2202 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 int number_of_literals = fun->NumberOfLiterals();
2204 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002207 // Insert the object, regexp and array functions in the literals
2208 // array prefix. These are the functions that will be used when
2209 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002210 literals->set(JSFunction::kLiteralGlobalContextIndex,
2211 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002213 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002215
2216 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2217 isolate->logger()->LogExistingFunction(
2218 shared, Handle<Code>(shared->code()));
2219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 }
2221
2222 target->set_context(*context);
2223 return *target;
2224}
2225
2226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002227RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002229 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002231 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002232 RUNTIME_ASSERT(num >= 0);
2233 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002235}
2236
2237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002238MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2239 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002241 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002242 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002244 }
2245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 2);
2253
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002254 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002256 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002258 uint32_t i = 0;
2259 if (index->IsSmi()) {
2260 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002262 i = value;
2263 } else {
2264 ASSERT(index->IsHeapNumber());
2265 double value = HeapNumber::cast(index)->value();
2266 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002267 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002268
2269 // Flatten the string. If someone wants to get a char at an index
2270 // in a cons string, it is likely that more indices will be
2271 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002272 Object* flat;
2273 { MaybeObject* maybe_flat = subject->TryFlatten();
2274 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2275 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 subject = String::cast(flat);
2277
2278 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002279 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002280 }
2281
2282 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002283}
2284
2285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002286RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287 NoHandleAllocation ha;
2288 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002289 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002290}
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292
2293class FixedArrayBuilder {
2294 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002295 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2296 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
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(initial_capacity > 0);
2302 }
2303
2304 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2305 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002306 length_(0),
2307 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002308 // Require a non-zero initial size. Ensures that doubling the size to
2309 // extend the array will work.
2310 ASSERT(backing_store->length() > 0);
2311 }
2312
2313 bool HasCapacity(int elements) {
2314 int length = array_->length();
2315 int required_length = length_ + elements;
2316 return (length >= required_length);
2317 }
2318
2319 void EnsureCapacity(int elements) {
2320 int length = array_->length();
2321 int required_length = length_ + elements;
2322 if (length < required_length) {
2323 int new_length = length;
2324 do {
2325 new_length *= 2;
2326 } while (new_length < required_length);
2327 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 array_->CopyTo(0, *extended_array, 0, length_);
2330 array_ = extended_array;
2331 }
2332 }
2333
2334 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002335 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002336 ASSERT(length_ < capacity());
2337 array_->set(length_, value);
2338 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002339 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 }
2341
2342 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002343 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 ASSERT(length_ < capacity());
2345 array_->set(length_, value);
2346 length_++;
2347 }
2348
2349 Handle<FixedArray> array() {
2350 return array_;
2351 }
2352
2353 int length() {
2354 return length_;
2355 }
2356
2357 int capacity() {
2358 return array_->length();
2359 }
2360
2361 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002362 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 result_array->set_length(Smi::FromInt(length_));
2364 return result_array;
2365 }
2366
2367 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002368 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002369 target_array->set_length(Smi::FromInt(length_));
2370 return target_array;
2371 }
2372
2373 private:
2374 Handle<FixedArray> array_;
2375 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002376 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377};
2378
2379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381const int kStringBuilderConcatHelperLengthBits = 11;
2382const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383
2384template <typename schar>
2385static inline void StringBuilderConcatHelper(String*,
2386 schar*,
2387 FixedArray*,
2388 int);
2389
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2391 StringBuilderSubstringLength;
2392typedef BitField<int,
2393 kStringBuilderConcatHelperLengthBits,
2394 kStringBuilderConcatHelperPositionBits>
2395 StringBuilderSubstringPosition;
2396
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397
2398class ReplacementStringBuilder {
2399 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002400 ReplacementStringBuilder(Heap* heap,
2401 Handle<String> subject,
2402 int estimated_part_count)
2403 : heap_(heap),
2404 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 // Require a non-zero initial size. Ensures that doubling the size to
2409 // extend the array will work.
2410 ASSERT(estimated_part_count > 0);
2411 }
2412
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2414 int from,
2415 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002416 ASSERT(from >= 0);
2417 int length = to - from;
2418 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 if (StringBuilderSubstringLength::is_valid(length) &&
2420 StringBuilderSubstringPosition::is_valid(from)) {
2421 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2422 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002423 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002425 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 builder->Add(Smi::FromInt(-length));
2427 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002429 }
2430
2431
2432 void EnsureCapacity(int elements) {
2433 array_builder_.EnsureCapacity(elements);
2434 }
2435
2436
2437 void AddSubjectSlice(int from, int to) {
2438 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002439 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441
2442
2443 void AddString(Handle<String> string) {
2444 int length = string->length();
2445 ASSERT(length > 0);
2446 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002447 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 is_ascii_ = false;
2449 }
2450 IncrementCharacterCount(length);
2451 }
2452
2453
2454 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002456 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 }
2458
2459 Handle<String> joined_string;
2460 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 char* char_buffer = seq->GetChars();
2464 StringBuilderConcatHelper(*subject_,
2465 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 *array_builder_.array(),
2467 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002468 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 } else {
2470 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 uc16* char_buffer = seq->GetChars();
2474 StringBuilderConcatHelper(*subject_,
2475 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 *array_builder_.array(),
2477 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 }
2480 return joined_string;
2481 }
2482
2483
2484 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002485 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002486 V8::FatalProcessOutOfMemory("String.replace result too large.");
2487 }
2488 character_count_ += by;
2489 }
2490
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002493 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002494
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002496 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2497 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 }
2499
2500
ager@chromium.org04921a82011-06-27 13:21:41 +00002501 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2502 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 }
2504
2505
2506 void AddElement(Object* element) {
2507 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002508 ASSERT(array_builder_.capacity() > array_builder_.length());
2509 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 }
2511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int character_count_;
2516 bool is_ascii_;
2517};
2518
2519
2520class CompiledReplacement {
2521 public:
2522 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002523 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002524
2525 void Compile(Handle<String> replacement,
2526 int capture_count,
2527 int subject_length);
2528
2529 void Apply(ReplacementStringBuilder* builder,
2530 int match_from,
2531 int match_to,
2532 Handle<JSArray> last_match_info);
2533
2534 // Number of distinct parts of the replacement pattern.
2535 int parts() {
2536 return parts_.length();
2537 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002538
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002539 bool simple_hint() {
2540 return simple_hint_;
2541 }
2542
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002543 private:
2544 enum PartType {
2545 SUBJECT_PREFIX = 1,
2546 SUBJECT_SUFFIX,
2547 SUBJECT_CAPTURE,
2548 REPLACEMENT_SUBSTRING,
2549 REPLACEMENT_STRING,
2550
2551 NUMBER_OF_PART_TYPES
2552 };
2553
2554 struct ReplacementPart {
2555 static inline ReplacementPart SubjectMatch() {
2556 return ReplacementPart(SUBJECT_CAPTURE, 0);
2557 }
2558 static inline ReplacementPart SubjectCapture(int capture_index) {
2559 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2560 }
2561 static inline ReplacementPart SubjectPrefix() {
2562 return ReplacementPart(SUBJECT_PREFIX, 0);
2563 }
2564 static inline ReplacementPart SubjectSuffix(int subject_length) {
2565 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2566 }
2567 static inline ReplacementPart ReplacementString() {
2568 return ReplacementPart(REPLACEMENT_STRING, 0);
2569 }
2570 static inline ReplacementPart ReplacementSubString(int from, int to) {
2571 ASSERT(from >= 0);
2572 ASSERT(to > from);
2573 return ReplacementPart(-from, to);
2574 }
2575
2576 // If tag <= 0 then it is the negation of a start index of a substring of
2577 // the replacement pattern, otherwise it's a value from PartType.
2578 ReplacementPart(int tag, int data)
2579 : tag(tag), data(data) {
2580 // Must be non-positive or a PartType value.
2581 ASSERT(tag < NUMBER_OF_PART_TYPES);
2582 }
2583 // Either a value of PartType or a non-positive number that is
2584 // the negation of an index into the replacement string.
2585 int tag;
2586 // The data value's interpretation depends on the value of tag:
2587 // tag == SUBJECT_PREFIX ||
2588 // tag == SUBJECT_SUFFIX: data is unused.
2589 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2590 // tag == REPLACEMENT_SUBSTRING ||
2591 // tag == REPLACEMENT_STRING: data is index into array of substrings
2592 // of the replacement string.
2593 // tag <= 0: Temporary representation of the substring of the replacement
2594 // string ranging over -tag .. data.
2595 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2596 // substring objects.
2597 int data;
2598 };
2599
2600 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002601 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002602 Vector<Char> characters,
2603 int capture_count,
2604 int subject_length) {
2605 int length = characters.length();
2606 int last = 0;
2607 for (int i = 0; i < length; i++) {
2608 Char c = characters[i];
2609 if (c == '$') {
2610 int next_index = i + 1;
2611 if (next_index == length) { // No next character!
2612 break;
2613 }
2614 Char c2 = characters[next_index];
2615 switch (c2) {
2616 case '$':
2617 if (i > last) {
2618 // There is a substring before. Include the first "$".
2619 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2620 last = next_index + 1; // Continue after the second "$".
2621 } else {
2622 // Let the next substring start with the second "$".
2623 last = next_index;
2624 }
2625 i = next_index;
2626 break;
2627 case '`':
2628 if (i > last) {
2629 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2630 }
2631 parts->Add(ReplacementPart::SubjectPrefix());
2632 i = next_index;
2633 last = i + 1;
2634 break;
2635 case '\'':
2636 if (i > last) {
2637 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2638 }
2639 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2640 i = next_index;
2641 last = i + 1;
2642 break;
2643 case '&':
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
2647 parts->Add(ReplacementPart::SubjectMatch());
2648 i = next_index;
2649 last = i + 1;
2650 break;
2651 case '0':
2652 case '1':
2653 case '2':
2654 case '3':
2655 case '4':
2656 case '5':
2657 case '6':
2658 case '7':
2659 case '8':
2660 case '9': {
2661 int capture_ref = c2 - '0';
2662 if (capture_ref > capture_count) {
2663 i = next_index;
2664 continue;
2665 }
2666 int second_digit_index = next_index + 1;
2667 if (second_digit_index < length) {
2668 // Peek ahead to see if we have two digits.
2669 Char c3 = characters[second_digit_index];
2670 if ('0' <= c3 && c3 <= '9') { // Double digits.
2671 int double_digit_ref = capture_ref * 10 + c3 - '0';
2672 if (double_digit_ref <= capture_count) {
2673 next_index = second_digit_index;
2674 capture_ref = double_digit_ref;
2675 }
2676 }
2677 }
2678 if (capture_ref > 0) {
2679 if (i > last) {
2680 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2681 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002682 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2684 last = next_index + 1;
2685 }
2686 i = next_index;
2687 break;
2688 }
2689 default:
2690 i = next_index;
2691 break;
2692 }
2693 }
2694 }
2695 if (length > last) {
2696 if (last == 0) {
2697 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002698 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 } else {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2701 }
2702 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
2705
2706 ZoneList<ReplacementPart> parts_;
2707 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002708 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002709};
2710
2711
2712void CompiledReplacement::Compile(Handle<String> replacement,
2713 int capture_count,
2714 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 String::FlatContent content = replacement->GetFlatContent();
2718 ASSERT(content.IsFlat());
2719 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002720 simple_hint_ = ParseReplacementPattern(&parts_,
2721 content.ToAsciiVector(),
2722 capture_count,
2723 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002724 } else {
2725 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002726 simple_hint_ = ParseReplacementPattern(&parts_,
2727 content.ToUC16Vector(),
2728 capture_count,
2729 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002730 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002731 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002733 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int substring_index = 0;
2735 for (int i = 0, n = parts_.length(); i < n; i++) {
2736 int tag = parts_[i].tag;
2737 if (tag <= 0) { // A replacement string slice.
2738 int from = -tag;
2739 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 replacement_substrings_.Add(
2741 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 parts_[i].tag = REPLACEMENT_SUBSTRING;
2743 parts_[i].data = substring_index;
2744 substring_index++;
2745 } else if (tag == REPLACEMENT_STRING) {
2746 replacement_substrings_.Add(replacement);
2747 parts_[i].data = substring_index;
2748 substring_index++;
2749 }
2750 }
2751}
2752
2753
2754void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2755 int match_from,
2756 int match_to,
2757 Handle<JSArray> last_match_info) {
2758 for (int i = 0, n = parts_.length(); i < n; i++) {
2759 ReplacementPart part = parts_[i];
2760 switch (part.tag) {
2761 case SUBJECT_PREFIX:
2762 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2763 break;
2764 case SUBJECT_SUFFIX: {
2765 int subject_length = part.data;
2766 if (match_to < subject_length) {
2767 builder->AddSubjectSlice(match_to, subject_length);
2768 }
2769 break;
2770 }
2771 case SUBJECT_CAPTURE: {
2772 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002773 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2775 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2776 if (from >= 0 && to > from) {
2777 builder->AddSubjectSlice(from, to);
2778 }
2779 break;
2780 }
2781 case REPLACEMENT_SUBSTRING:
2782 case REPLACEMENT_STRING:
2783 builder->AddString(replacement_substrings_[part.data]);
2784 break;
2785 default:
2786 UNREACHABLE();
2787 }
2788 }
2789}
2790
2791
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002792void FindAsciiStringIndices(Vector<const char> subject,
2793 char pattern,
2794 ZoneList<int>* indices,
2795 unsigned int limit) {
2796 ASSERT(limit > 0);
2797 // Collect indices of pattern in subject using memchr.
2798 // Stop after finding at most limit values.
2799 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2800 const char* subject_end = subject_start + subject.length();
2801 const char* pos = subject_start;
2802 while (limit > 0) {
2803 pos = reinterpret_cast<const char*>(
2804 memchr(pos, pattern, subject_end - pos));
2805 if (pos == NULL) return;
2806 indices->Add(static_cast<int>(pos - subject_start));
2807 pos++;
2808 limit--;
2809 }
2810}
2811
2812
2813template <typename SubjectChar, typename PatternChar>
2814void FindStringIndices(Isolate* isolate,
2815 Vector<const SubjectChar> subject,
2816 Vector<const PatternChar> pattern,
2817 ZoneList<int>* indices,
2818 unsigned int limit) {
2819 ASSERT(limit > 0);
2820 // Collect indices of pattern in subject.
2821 // Stop after finding at most limit values.
2822 int pattern_length = pattern.length();
2823 int index = 0;
2824 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2825 while (limit > 0) {
2826 index = search.Search(subject, index);
2827 if (index < 0) return;
2828 indices->Add(index);
2829 index += pattern_length;
2830 limit--;
2831 }
2832}
2833
2834
2835void FindStringIndicesDispatch(Isolate* isolate,
2836 String* subject,
2837 String* pattern,
2838 ZoneList<int>* indices,
2839 unsigned int limit) {
2840 {
2841 AssertNoAllocation no_gc;
2842 String::FlatContent subject_content = subject->GetFlatContent();
2843 String::FlatContent pattern_content = pattern->GetFlatContent();
2844 ASSERT(subject_content.IsFlat());
2845 ASSERT(pattern_content.IsFlat());
2846 if (subject_content.IsAscii()) {
2847 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2848 if (pattern_content.IsAscii()) {
2849 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2850 if (pattern_vector.length() == 1) {
2851 FindAsciiStringIndices(subject_vector,
2852 pattern_vector[0],
2853 indices,
2854 limit);
2855 } else {
2856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_vector,
2859 indices,
2860 limit);
2861 }
2862 } else {
2863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToUC16Vector(),
2866 indices,
2867 limit);
2868 }
2869 } else {
2870 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002871 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002872 FindStringIndices(isolate,
2873 subject_vector,
2874 pattern_content.ToAsciiVector(),
2875 indices,
2876 limit);
2877 } else {
2878 FindStringIndices(isolate,
2879 subject_vector,
2880 pattern_content.ToUC16Vector(),
2881 indices,
2882 limit);
2883 }
2884 }
2885 }
2886}
2887
2888
2889template<typename ResultSeqString>
2890MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2891 Isolate* isolate,
2892 Handle<String> subject,
2893 Handle<JSRegExp> pattern_regexp,
2894 Handle<String> replacement) {
2895 ASSERT(subject->IsFlat());
2896 ASSERT(replacement->IsFlat());
2897
2898 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2899 ZoneList<int> indices(8);
2900 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2901 String* pattern =
2902 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2903 int subject_len = subject->length();
2904 int pattern_len = pattern->length();
2905 int replacement_len = replacement->length();
2906
2907 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2908
2909 int matches = indices.length();
2910 if (matches == 0) return *subject;
2911
2912 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2913 int subject_pos = 0;
2914 int result_pos = 0;
2915
2916 Handle<ResultSeqString> result;
2917 if (ResultSeqString::kHasAsciiEncoding) {
2918 result = Handle<ResultSeqString>::cast(
2919 isolate->factory()->NewRawAsciiString(result_len));
2920 } else {
2921 result = Handle<ResultSeqString>::cast(
2922 isolate->factory()->NewRawTwoByteString(result_len));
2923 }
2924
2925 for (int i = 0; i < matches; i++) {
2926 // Copy non-matched subject content.
2927 if (subject_pos < indices.at(i)) {
2928 String::WriteToFlat(*subject,
2929 result->GetChars() + result_pos,
2930 subject_pos,
2931 indices.at(i));
2932 result_pos += indices.at(i) - subject_pos;
2933 }
2934
2935 // Replace match.
2936 if (replacement_len > 0) {
2937 String::WriteToFlat(*replacement,
2938 result->GetChars() + result_pos,
2939 0,
2940 replacement_len);
2941 result_pos += replacement_len;
2942 }
2943
2944 subject_pos = indices.at(i) + pattern_len;
2945 }
2946 // Add remaining subject content at the end.
2947 if (subject_pos < subject_len) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 subject_len);
2952 }
2953 return *result;
2954}
2955
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002956
lrn@chromium.org303ada72010-10-27 09:33:13 +00002957MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002958 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002959 String* subject,
2960 JSRegExp* regexp,
2961 String* replacement,
2962 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002963 ASSERT(subject->IsFlat());
2964 ASSERT(replacement->IsFlat());
2965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002967
2968 int length = subject->length();
2969 Handle<String> subject_handle(subject);
2970 Handle<JSRegExp> regexp_handle(regexp);
2971 Handle<String> replacement_handle(replacement);
2972 Handle<JSArray> last_match_info_handle(last_match_info);
2973 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2974 subject_handle,
2975 0,
2976 last_match_info_handle);
2977 if (match.is_null()) {
2978 return Failure::Exception();
2979 }
2980 if (match->IsNull()) {
2981 return *subject_handle;
2982 }
2983
2984 int capture_count = regexp_handle->CaptureCount();
2985
2986 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002987 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002988 CompiledReplacement compiled_replacement;
2989 compiled_replacement.Compile(replacement_handle,
2990 capture_count,
2991 length);
2992
2993 bool is_global = regexp_handle->GetFlags().is_global();
2994
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002995 // Shortcut for simple non-regexp global replacements
2996 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002997 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002998 compiled_replacement.simple_hint()) {
2999 if (subject_handle->HasOnlyAsciiChars() &&
3000 replacement_handle->HasOnlyAsciiChars()) {
3001 return StringReplaceStringWithString<SeqAsciiString>(
3002 isolate, subject_handle, regexp_handle, replacement_handle);
3003 } else {
3004 return StringReplaceStringWithString<SeqTwoByteString>(
3005 isolate, subject_handle, regexp_handle, replacement_handle);
3006 }
3007 }
3008
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003009 // Guessing the number of parts that the final result string is built
3010 // from. Global regexps can match any number of times, so we guess
3011 // conservatively.
3012 int expected_parts =
3013 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003014 ReplacementStringBuilder builder(isolate->heap(),
3015 subject_handle,
3016 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003017
3018 // Index of end of last match.
3019 int prev = 0;
3020
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003021 // Number of parts added by compiled replacement plus preceeding
3022 // string and possibly suffix after last match. It is possible for
3023 // all components to use two elements when encoded as two smis.
3024 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025 bool matched = true;
3026 do {
3027 ASSERT(last_match_info_handle->HasFastElements());
3028 // Increase the capacity of the builder before entering local handle-scope,
3029 // so its internal buffer can safely allocate a new handle if it grows.
3030 builder.EnsureCapacity(parts_added_per_loop);
3031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003032 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int start, end;
3034 {
3035 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003036 FixedArray* match_info_array =
3037 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003038
3039 ASSERT_EQ(capture_count * 2 + 2,
3040 RegExpImpl::GetLastCaptureCount(match_info_array));
3041 start = RegExpImpl::GetCapture(match_info_array, 0);
3042 end = RegExpImpl::GetCapture(match_info_array, 1);
3043 }
3044
3045 if (prev < start) {
3046 builder.AddSubjectSlice(prev, start);
3047 }
3048 compiled_replacement.Apply(&builder,
3049 start,
3050 end,
3051 last_match_info_handle);
3052 prev = end;
3053
3054 // Only continue checking for global regexps.
3055 if (!is_global) break;
3056
3057 // Continue from where the match ended, unless it was an empty match.
3058 int next = end;
3059 if (start == end) {
3060 next = end + 1;
3061 if (next > length) break;
3062 }
3063
3064 match = RegExpImpl::Exec(regexp_handle,
3065 subject_handle,
3066 next,
3067 last_match_info_handle);
3068 if (match.is_null()) {
3069 return Failure::Exception();
3070 }
3071 matched = !match->IsNull();
3072 } while (matched);
3073
3074 if (prev < length) {
3075 builder.AddSubjectSlice(prev, length);
3076 }
3077
3078 return *(builder.ToString());
3079}
3080
3081
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003083MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003085 String* subject,
3086 JSRegExp* regexp,
3087 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 ASSERT(subject->IsFlat());
3089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003090 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003091
3092 Handle<String> subject_handle(subject);
3093 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003094
3095 // Shortcut for simple non-regexp global replacements
3096 if (regexp_handle->GetFlags().is_global() &&
3097 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3098 Handle<String> empty_string_handle(HEAP->empty_string());
3099 if (subject_handle->HasOnlyAsciiChars()) {
3100 return StringReplaceStringWithString<SeqAsciiString>(
3101 isolate, subject_handle, regexp_handle, empty_string_handle);
3102 } else {
3103 return StringReplaceStringWithString<SeqTwoByteString>(
3104 isolate, subject_handle, regexp_handle, empty_string_handle);
3105 }
3106 }
3107
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 Handle<JSArray> last_match_info_handle(last_match_info);
3109 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3110 subject_handle,
3111 0,
3112 last_match_info_handle);
3113 if (match.is_null()) return Failure::Exception();
3114 if (match->IsNull()) return *subject_handle;
3115
3116 ASSERT(last_match_info_handle->HasFastElements());
3117
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003118 int start, end;
3119 {
3120 AssertNoAllocation match_info_array_is_not_in_a_handle;
3121 FixedArray* match_info_array =
3122 FixedArray::cast(last_match_info_handle->elements());
3123
3124 start = RegExpImpl::GetCapture(match_info_array, 0);
3125 end = RegExpImpl::GetCapture(match_info_array, 1);
3126 }
3127
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003128 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003129 int new_length = length - (end - start);
3130 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003132 }
3133 Handle<ResultSeqString> answer;
3134 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003135 answer = Handle<ResultSeqString>::cast(
3136 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003137 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 answer = Handle<ResultSeqString>::cast(
3139 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003140 }
3141
3142 // If the regexp isn't global, only match once.
3143 if (!regexp_handle->GetFlags().is_global()) {
3144 if (start > 0) {
3145 String::WriteToFlat(*subject_handle,
3146 answer->GetChars(),
3147 0,
3148 start);
3149 }
3150 if (end < length) {
3151 String::WriteToFlat(*subject_handle,
3152 answer->GetChars() + start,
3153 end,
3154 length);
3155 }
3156 return *answer;
3157 }
3158
3159 int prev = 0; // Index of end of last match.
3160 int next = 0; // Start of next search (prev unless last match was empty).
3161 int position = 0;
3162
3163 do {
3164 if (prev < start) {
3165 // Add substring subject[prev;start] to answer string.
3166 String::WriteToFlat(*subject_handle,
3167 answer->GetChars() + position,
3168 prev,
3169 start);
3170 position += start - prev;
3171 }
3172 prev = end;
3173 next = end;
3174 // Continue from where the match ended, unless it was an empty match.
3175 if (start == end) {
3176 next++;
3177 if (next > length) break;
3178 }
3179 match = RegExpImpl::Exec(regexp_handle,
3180 subject_handle,
3181 next,
3182 last_match_info_handle);
3183 if (match.is_null()) return Failure::Exception();
3184 if (match->IsNull()) break;
3185
3186 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188 {
3189 AssertNoAllocation match_info_array_is_not_in_a_handle;
3190 FixedArray* match_info_array =
3191 FixedArray::cast(last_match_info_handle->elements());
3192 start = RegExpImpl::GetCapture(match_info_array, 0);
3193 end = RegExpImpl::GetCapture(match_info_array, 1);
3194 }
3195 } while (true);
3196
3197 if (prev < length) {
3198 // Add substring subject[prev;length] to answer string.
3199 String::WriteToFlat(*subject_handle,
3200 answer->GetChars() + position,
3201 prev,
3202 length);
3203 position += length - prev;
3204 }
3205
3206 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 }
3209
3210 // Shorten string and fill
3211 int string_size = ResultSeqString::SizeFor(position);
3212 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3213 int delta = allocated_string_size - string_size;
3214
3215 answer->set_length(position);
3216 if (delta == 0) return *answer;
3217
3218 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003219 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003220 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003221 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003222 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223
3224 return *answer;
3225}
3226
3227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003228RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 ASSERT(args.length() == 4);
3230
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003231 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003233 Object* flat_subject;
3234 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3235 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3236 return maybe_flat_subject;
3237 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238 }
3239 subject = String::cast(flat_subject);
3240 }
3241
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003242 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003243 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003244 Object* flat_replacement;
3245 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3246 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3247 return maybe_flat_replacement;
3248 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 }
3250 replacement = String::cast(flat_replacement);
3251 }
3252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003253 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3254 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255
3256 ASSERT(last_match_info->HasFastElements());
3257
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003258 if (replacement->length() == 0) {
3259 if (subject->HasOnlyAsciiChars()) {
3260 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003262 } else {
3263 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003265 }
3266 }
3267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 return StringReplaceRegExpWithString(isolate,
3269 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003270 regexp,
3271 replacement,
3272 last_match_info);
3273}
3274
3275
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003276Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3277 Handle<String> subject,
3278 Handle<String> search,
3279 Handle<String> replace,
3280 bool* found,
3281 int recursion_limit) {
3282 if (recursion_limit == 0) return Handle<String>::null();
3283 if (subject->IsConsString()) {
3284 ConsString* cons = ConsString::cast(*subject);
3285 Handle<String> first = Handle<String>(cons->first());
3286 Handle<String> second = Handle<String>(cons->second());
3287 Handle<String> new_first =
3288 StringReplaceOneCharWithString(isolate,
3289 first,
3290 search,
3291 replace,
3292 found,
3293 recursion_limit - 1);
3294 if (*found) return isolate->factory()->NewConsString(new_first, second);
3295 if (new_first.is_null()) return new_first;
3296
3297 Handle<String> new_second =
3298 StringReplaceOneCharWithString(isolate,
3299 second,
3300 search,
3301 replace,
3302 found,
3303 recursion_limit - 1);
3304 if (*found) return isolate->factory()->NewConsString(first, new_second);
3305 if (new_second.is_null()) return new_second;
3306
3307 return subject;
3308 } else {
3309 int index = StringMatch(isolate, subject, search, 0);
3310 if (index == -1) return subject;
3311 *found = true;
3312 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3313 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3314 Handle<String> second =
3315 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3316 return isolate->factory()->NewConsString(cons1, second);
3317 }
3318}
3319
3320
3321RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3322 ASSERT(args.length() == 3);
3323 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003324 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3325 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3326 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003327
3328 // If the cons string tree is too deep, we simply abort the recursion and
3329 // retry with a flattened subject string.
3330 const int kRecursionLimit = 0x1000;
3331 bool found = false;
3332 Handle<String> result =
3333 Runtime::StringReplaceOneCharWithString(isolate,
3334 subject,
3335 search,
3336 replace,
3337 &found,
3338 kRecursionLimit);
3339 if (!result.is_null()) return *result;
3340 return *Runtime::StringReplaceOneCharWithString(isolate,
3341 FlattenGetString(subject),
3342 search,
3343 replace,
3344 &found,
3345 kRecursionLimit);
3346}
3347
3348
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349// Perform string match of pattern on subject, starting at start index.
3350// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003351// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352int Runtime::StringMatch(Isolate* isolate,
3353 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 Handle<String> pat,
3355 int start_index) {
3356 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003358
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003359 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003360 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003362 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003363 if (start_index + pattern_length > subject_length) return -1;
3364
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003365 if (!sub->IsFlat()) FlattenString(sub);
3366 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003367
ager@chromium.org7c537e22008-10-16 08:43:32 +00003368 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003369 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 String::FlatContent seq_sub = sub->GetFlatContent();
3371 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003372
ager@chromium.org7c537e22008-10-16 08:43:32 +00003373 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 if (seq_pat.IsAscii()) {
3375 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3376 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 pat_vector,
3380 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 pat_vector,
3385 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003386 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003387 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3388 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003390 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003391 pat_vector,
3392 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003394 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 pat_vector,
3397 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003398}
3399
3400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003401RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003402 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003403 ASSERT(args.length() == 3);
3404
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003405 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3406 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003407
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003408 Object* index = args[2];
3409 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003410 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003411
ager@chromium.org870a0b62008-11-04 11:43:05 +00003412 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003413 int position =
3414 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003415 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416}
3417
3418
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003419template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003420static int StringMatchBackwards(Vector<const schar> subject,
3421 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 int pattern_length = pattern.length();
3424 ASSERT(pattern_length >= 1);
3425 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426
3427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003428 for (int i = 0; i < pattern_length; i++) {
3429 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 if (c > String::kMaxAsciiCharCode) {
3431 return -1;
3432 }
3433 }
3434 }
3435
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003436 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003438 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003440 while (j < pattern_length) {
3441 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442 break;
3443 }
3444 j++;
3445 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003446 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447 return i;
3448 }
3449 }
3450 return -1;
3451}
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 ASSERT(args.length() == 3);
3456
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003457 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3458 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003462 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003464 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003465 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467 if (start_index + pat_length > sub_length) {
3468 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003471 if (pat_length == 0) {
3472 return Smi::FromInt(start_index);
3473 }
3474
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003475 if (!sub->IsFlat()) FlattenString(sub);
3476 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003477
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003478 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3480
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003481 String::FlatContent sub_content = sub->GetFlatContent();
3482 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003484 if (pat_content.IsAscii()) {
3485 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3486 if (sub_content.IsAscii()) {
3487 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003488 pat_vector,
3489 start_index);
3490 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003491 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003492 pat_vector,
3493 start_index);
3494 }
3495 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003496 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3497 if (sub_content.IsAscii()) {
3498 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003499 pat_vector,
3500 start_index);
3501 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003502 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003503 pat_vector,
3504 start_index);
3505 }
3506 }
3507
3508 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509}
3510
3511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003512RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 NoHandleAllocation ha;
3514 ASSERT(args.length() == 2);
3515
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003516 CONVERT_ARG_CHECKED(String, str1, 0);
3517 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
3519 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 int str1_length = str1->length();
3521 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522
3523 // Decide trivial cases without flattening.
3524 if (str1_length == 0) {
3525 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3526 return Smi::FromInt(-str2_length);
3527 } else {
3528 if (str2_length == 0) return Smi::FromInt(str1_length);
3529 }
3530
3531 int end = str1_length < str2_length ? str1_length : str2_length;
3532
3533 // No need to flatten if we are going to find the answer on the first
3534 // character. At this point we know there is at least one character
3535 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003536 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 if (d != 0) return Smi::FromInt(d);
3538
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003539 str1->TryFlatten();
3540 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 StringInputBuffer& buf1 =
3543 *isolate->runtime_state()->string_locale_compare_buf1();
3544 StringInputBuffer& buf2 =
3545 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546
3547 buf1.Reset(str1);
3548 buf2.Reset(str2);
3549
3550 for (int i = 0; i < end; i++) {
3551 uint16_t char1 = buf1.GetNext();
3552 uint16_t char2 = buf2.GetNext();
3553 if (char1 != char2) return Smi::FromInt(char1 - char2);
3554 }
3555
3556 return Smi::FromInt(str1_length - str2_length);
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 3);
3563
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003564 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003565 int start, end;
3566 // We have a fast integer-only case here to avoid a conversion to double in
3567 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003568 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3569 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3570 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3571 start = from_number;
3572 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003573 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3575 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003576 start = FastD2I(from_number);
3577 end = FastD2I(to_number);
3578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 RUNTIME_ASSERT(end >= start);
3580 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003581 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003583 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584}
3585
3586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003587RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003588 ASSERT_EQ(3, args.length());
3589
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3591 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3592 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 HandleScope handles;
3594
3595 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3596
3597 if (match.is_null()) {
3598 return Failure::Exception();
3599 }
3600 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003602 }
3603 int length = subject->length();
3604
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003605 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003606 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 int start;
3608 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003609 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003610 {
3611 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003612 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3614 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3615 }
3616 offsets.Add(start);
3617 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003618 if (start == end) if (++end > length) break;
3619 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 if (match.is_null()) {
3621 return Failure::Exception();
3622 }
3623 } while (!match->IsNull());
3624 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003626 Handle<String> substring = isolate->factory()->
3627 NewSubString(subject, offsets.at(0), offsets.at(1));
3628 elements->set(0, *substring);
3629 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003630 int from = offsets.at(i * 2);
3631 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003632 Handle<String> substring = isolate->factory()->
3633 NewProperSubString(subject, from, to);
3634 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003635 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003637 result->set_length(Smi::FromInt(matches));
3638 return *result;
3639}
3640
3641
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642// Two smis before and after the match, for very long strings.
3643const int kMaxBuilderEntriesPerRegExpMatch = 5;
3644
3645
3646static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3647 Handle<JSArray> last_match_info,
3648 int match_start,
3649 int match_end) {
3650 // Fill last_match_info with a single capture.
3651 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3652 AssertNoAllocation no_gc;
3653 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3654 RegExpImpl::SetLastCaptureCount(elements, 2);
3655 RegExpImpl::SetLastInput(elements, *subject);
3656 RegExpImpl::SetLastSubject(elements, *subject);
3657 RegExpImpl::SetCapture(elements, 0, match_start);
3658 RegExpImpl::SetCapture(elements, 1, match_end);
3659}
3660
3661
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663static bool SearchStringMultiple(Isolate* isolate,
3664 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 Vector<const PatternChar> pattern,
3666 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003667 FixedArrayBuilder* builder,
3668 int* match_pos) {
3669 int pos = *match_pos;
3670 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003671 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003674 while (pos <= max_search_start) {
3675 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3676 *match_pos = pos;
3677 return false;
3678 }
3679 // Position of end of previous match.
3680 int match_end = pos + pattern_length;
3681 int new_pos = search.Search(subject, match_end);
3682 if (new_pos >= 0) {
3683 // A match.
3684 if (new_pos > match_end) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003688 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003689 pos = new_pos;
3690 builder->Add(pattern_string);
3691 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003693 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003695
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 if (pos < max_search_start) {
3697 ReplacementStringBuilder::AddSubjectSlice(builder,
3698 pos + pattern_length,
3699 subject_length);
3700 }
3701 *match_pos = pos;
3702 return true;
3703}
3704
3705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706static bool SearchStringMultiple(Isolate* isolate,
3707 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003708 Handle<String> pattern,
3709 Handle<JSArray> last_match_info,
3710 FixedArrayBuilder* builder) {
3711 ASSERT(subject->IsFlat());
3712 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713
3714 // Treating as if a previous match was before first character.
3715 int match_pos = -pattern->length();
3716
3717 for (;;) { // Break when search complete.
3718 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3719 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003720 String::FlatContent subject_content = subject->GetFlatContent();
3721 String::FlatContent pattern_content = pattern->GetFlatContent();
3722 if (subject_content.IsAscii()) {
3723 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3724 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003727 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003728 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 builder,
3730 &match_pos)) break;
3731 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003734 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003735 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736 builder,
3737 &match_pos)) break;
3738 }
3739 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003740 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3741 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 if (SearchStringMultiple(isolate,
3743 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003744 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003745 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003746 builder,
3747 &match_pos)) break;
3748 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003749 if (SearchStringMultiple(isolate,
3750 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003751 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003752 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003753 builder,
3754 &match_pos)) break;
3755 }
3756 }
3757 }
3758
3759 if (match_pos >= 0) {
3760 SetLastMatchInfoNoCaptures(subject,
3761 last_match_info,
3762 match_pos,
3763 match_pos + pattern->length());
3764 return true;
3765 }
3766 return false; // No matches at all.
3767}
3768
3769
3770static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003772 Handle<String> subject,
3773 Handle<JSRegExp> regexp,
3774 Handle<JSArray> last_match_array,
3775 FixedArrayBuilder* builder) {
3776 ASSERT(subject->IsFlat());
3777 int match_start = -1;
3778 int match_end = 0;
3779 int pos = 0;
3780 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3781 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3782
ulan@chromium.org812308e2012-02-29 15:58:45 +00003783 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003784 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003785 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003786 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003787
3788 for (;;) { // Break on failure, return on exception.
3789 RegExpImpl::IrregexpResult result =
3790 RegExpImpl::IrregexpExecOnce(regexp,
3791 subject,
3792 pos,
3793 register_vector);
3794 if (result == RegExpImpl::RE_SUCCESS) {
3795 match_start = register_vector[0];
3796 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3797 if (match_end < match_start) {
3798 ReplacementStringBuilder::AddSubjectSlice(builder,
3799 match_end,
3800 match_start);
3801 }
3802 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 if (!first) {
3805 builder->Add(*isolate->factory()->NewProperSubString(subject,
3806 match_start,
3807 match_end));
3808 } else {
3809 builder->Add(*isolate->factory()->NewSubString(subject,
3810 match_start,
3811 match_end));
3812 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003813 if (match_start != match_end) {
3814 pos = match_end;
3815 } else {
3816 pos = match_end + 1;
3817 if (pos > subject_length) break;
3818 }
3819 } else if (result == RegExpImpl::RE_FAILURE) {
3820 break;
3821 } else {
3822 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3823 return result;
3824 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003825 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003826 }
3827
3828 if (match_start >= 0) {
3829 if (match_end < subject_length) {
3830 ReplacementStringBuilder::AddSubjectSlice(builder,
3831 match_end,
3832 subject_length);
3833 }
3834 SetLastMatchInfoNoCaptures(subject,
3835 last_match_array,
3836 match_start,
3837 match_end);
3838 return RegExpImpl::RE_SUCCESS;
3839 } else {
3840 return RegExpImpl::RE_FAILURE; // No matches at all.
3841 }
3842}
3843
3844
3845static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003846 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003847 Handle<String> subject,
3848 Handle<JSRegExp> regexp,
3849 Handle<JSArray> last_match_array,
3850 FixedArrayBuilder* builder) {
3851
3852 ASSERT(subject->IsFlat());
3853 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3854 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3855
ulan@chromium.org812308e2012-02-29 15:58:45 +00003856 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003857 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003858
3859 RegExpImpl::IrregexpResult result =
3860 RegExpImpl::IrregexpExecOnce(regexp,
3861 subject,
3862 0,
3863 register_vector);
3864
3865 int capture_count = regexp->CaptureCount();
3866 int subject_length = subject->length();
3867
3868 // Position to search from.
3869 int pos = 0;
3870 // End of previous match. Differs from pos if match was empty.
3871 int match_end = 0;
3872 if (result == RegExpImpl::RE_SUCCESS) {
3873 // Need to keep a copy of the previous match for creating last_match_info
3874 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003875 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003877 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 do {
3879 int match_start = register_vector[0];
3880 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3881 if (match_end < match_start) {
3882 ReplacementStringBuilder::AddSubjectSlice(builder,
3883 match_end,
3884 match_start);
3885 }
3886 match_end = register_vector[1];
3887
3888 {
3889 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 // Arguments array to replace function is match, captures, index and
3892 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893 Handle<FixedArray> elements =
3894 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 Handle<String> match;
3896 if (!first) {
3897 match = isolate->factory()->NewProperSubString(subject,
3898 match_start,
3899 match_end);
3900 } else {
3901 match = isolate->factory()->NewSubString(subject,
3902 match_start,
3903 match_end);
3904 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003905 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 for (int i = 1; i <= capture_count; i++) {
3907 int start = register_vector[i * 2];
3908 if (start >= 0) {
3909 int end = register_vector[i * 2 + 1];
3910 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003911 Handle<String> substring;
3912 if (!first) {
3913 substring = isolate->factory()->NewProperSubString(subject,
3914 start,
3915 end);
3916 } else {
3917 substring = isolate->factory()->NewSubString(subject, start, end);
3918 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 elements->set(i, *substring);
3920 } else {
3921 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 }
3924 }
3925 elements->set(capture_count + 1, Smi::FromInt(match_start));
3926 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003928 }
3929 // Swap register vectors, so the last successful match is in
3930 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003931 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 prev_register_vector = register_vector;
3933 register_vector = tmp;
3934
3935 if (match_end > match_start) {
3936 pos = match_end;
3937 } else {
3938 pos = match_end + 1;
3939 if (pos > subject_length) {
3940 break;
3941 }
3942 }
3943
3944 result = RegExpImpl::IrregexpExecOnce(regexp,
3945 subject,
3946 pos,
3947 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003948 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003949 } while (result == RegExpImpl::RE_SUCCESS);
3950
3951 if (result != RegExpImpl::RE_EXCEPTION) {
3952 // Finished matching, with at least one match.
3953 if (match_end < subject_length) {
3954 ReplacementStringBuilder::AddSubjectSlice(builder,
3955 match_end,
3956 subject_length);
3957 }
3958
3959 int last_match_capture_count = (capture_count + 1) * 2;
3960 int last_match_array_size =
3961 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3962 last_match_array->EnsureSize(last_match_array_size);
3963 AssertNoAllocation no_gc;
3964 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3965 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3966 RegExpImpl::SetLastSubject(elements, *subject);
3967 RegExpImpl::SetLastInput(elements, *subject);
3968 for (int i = 0; i < last_match_capture_count; i++) {
3969 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3970 }
3971 return RegExpImpl::RE_SUCCESS;
3972 }
3973 }
3974 // No matches at all, return failure or exception result directly.
3975 return result;
3976}
3977
3978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003979RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003980 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003982
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003983 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003984 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003985 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3986 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3987 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988
3989 ASSERT(last_match_info->HasFastElements());
3990 ASSERT(regexp->GetFlags().is_global());
3991 Handle<FixedArray> result_elements;
3992 if (result_array->HasFastElements()) {
3993 result_elements =
3994 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003995 }
3996 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 }
3999 FixedArrayBuilder builder(result_elements);
4000
4001 if (regexp->TypeTag() == JSRegExp::ATOM) {
4002 Handle<String> pattern(
4003 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004004 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 if (SearchStringMultiple(isolate, subject, pattern,
4006 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004007 return *builder.ToJSArray(result_array);
4008 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004010 }
4011
4012 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4013
4014 RegExpImpl::IrregexpResult result;
4015 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004016 result = SearchRegExpNoCaptureMultiple(isolate,
4017 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 regexp,
4019 last_match_info,
4020 &builder);
4021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 result = SearchRegExpMultiple(isolate,
4023 subject,
4024 regexp,
4025 last_match_info,
4026 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004027 }
4028 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004029 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004030 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4031 return Failure::Exception();
4032}
4033
4034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 NoHandleAllocation ha;
4037 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004039 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004041 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004042 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004043 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004044 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004045 // Character array used for conversion.
4046 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 return isolate->heap()->
4048 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004049 }
4050 }
4051
4052 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004053 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
4057 if (isinf(value)) {
4058 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004059 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004061 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 MaybeObject* result =
4065 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 DeleteArray(str);
4067 return result;
4068}
4069
4070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 NoHandleAllocation ha;
4073 ASSERT(args.length() == 2);
4074
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004075 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004077 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 }
4079 if (isinf(value)) {
4080 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004081 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004085 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 int f = FastD2I(f_number);
4087 RUNTIME_ASSERT(f >= 0);
4088 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 MaybeObject* res =
4090 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093}
4094
4095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 NoHandleAllocation ha;
4098 ASSERT(args.length() == 2);
4099
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004100 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004102 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
4104 if (isinf(value)) {
4105 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004106 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004108 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004110 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 int f = FastD2I(f_number);
4112 RUNTIME_ASSERT(f >= -1 && f <= 20);
4113 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004114 MaybeObject* res =
4115 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004117 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118}
4119
4120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 NoHandleAllocation ha;
4123 ASSERT(args.length() == 2);
4124
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004125 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004127 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 }
4129 if (isinf(value)) {
4130 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004133 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004135 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 int f = FastD2I(f_number);
4137 RUNTIME_ASSERT(f >= 1 && f <= 21);
4138 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 MaybeObject* res =
4140 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004142 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
4146// Returns a single character string where first character equals
4147// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004149 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004150 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004151 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004152 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155}
4156
4157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4159 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004160 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 // Handle [] indexing on Strings
4162 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004163 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4164 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 }
4166
4167 // Handle [] indexing on String objects
4168 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004169 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4170 Handle<Object> result =
4171 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4172 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 }
4174
4175 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004176 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 }
4178
4179 return object->GetElement(index);
4180}
4181
4182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4184 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004189 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004191 isolate->factory()->NewTypeError("non_object_property_load",
4192 HandleVector(args, 2));
4193 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 }
4195
4196 // Check if the given key is an array index.
4197 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004198 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 }
4201
4202 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004203 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207 bool has_pending_exception = false;
4208 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004211 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 }
4213
ager@chromium.org32912102009-01-16 10:38:43 +00004214 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215 // the element if so.
4216 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004219 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 }
4221}
4222
4223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 NoHandleAllocation ha;
4226 ASSERT(args.length() == 2);
4227
4228 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004229 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232}
4233
4234
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004235// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004237 NoHandleAllocation ha;
4238 ASSERT(args.length() == 2);
4239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004240 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004241 // itself.
4242 //
4243 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004244 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004245 // global proxy object never has properties. This is the case
4246 // because the global proxy object forwards everything to its hidden
4247 // prototype including local lookups.
4248 //
4249 // Additionally, we need to make sure that we do not cache results
4250 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004251 if (args[0]->IsJSObject()) {
4252 if (!args[0]->IsJSGlobalProxy() &&
4253 !args[0]->IsAccessCheckNeeded() &&
4254 args[1]->IsString()) {
4255 JSObject* receiver = JSObject::cast(args[0]);
4256 String* key = String::cast(args[1]);
4257 if (receiver->HasFastProperties()) {
4258 // Attempt to use lookup cache.
4259 Map* receiver_map = receiver->map();
4260 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4261 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4262 if (offset != -1) {
4263 Object* value = receiver->FastPropertyAt(offset);
4264 return value->IsTheHole()
4265 ? isolate->heap()->undefined_value()
4266 : value;
4267 }
4268 // Lookup cache miss. Perform lookup and update the cache if
4269 // appropriate.
4270 LookupResult result(isolate);
4271 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004272 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 int offset = result.GetFieldIndex();
4274 keyed_lookup_cache->Update(receiver_map, key, offset);
4275 return receiver->FastPropertyAt(offset);
4276 }
4277 } else {
4278 // Attempt dictionary lookup.
4279 StringDictionary* dictionary = receiver->property_dictionary();
4280 int entry = dictionary->FindEntry(key);
4281 if ((entry != StringDictionary::kNotFound) &&
4282 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4283 Object* value = dictionary->ValueAt(entry);
4284 if (!receiver->IsGlobalObject()) return value;
4285 value = JSGlobalPropertyCell::cast(value)->value();
4286 if (!value->IsTheHole()) return value;
4287 // If value is the hole do the general lookup.
4288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004289 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004290 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4291 // JSObject without a string key. If the key is a Smi, check for a
4292 // definite out-of-bounds access to elements, which is a strong indicator
4293 // that subsequent accesses will also call the runtime. Proactively
4294 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4295 // doubles for those future calls in the case that the elements would
4296 // become FAST_DOUBLE_ELEMENTS.
4297 Handle<JSObject> js_object(args.at<JSObject>(0));
4298 ElementsKind elements_kind = js_object->GetElementsKind();
4299 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4300 elements_kind == FAST_DOUBLE_ELEMENTS) {
4301 FixedArrayBase* elements = js_object->elements();
4302 if (args.at<Smi>(1)->value() >= elements->length()) {
4303 MaybeObject* maybe_object = TransitionElements(js_object,
4304 FAST_ELEMENTS,
4305 isolate);
4306 if (maybe_object->IsFailure()) return maybe_object;
4307 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004308 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004309 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004310 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4311 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004313 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004314 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004315 if (index >= 0 && index < str->length()) {
4316 Handle<Object> result = GetCharAt(str, index);
4317 return *result;
4318 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004319 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004320
4321 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004322 return Runtime::GetObjectProperty(isolate,
4323 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004324 args.at<Object>(1));
4325}
4326
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004327
4328static bool IsValidAccessor(Handle<Object> obj) {
4329 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4330}
4331
4332
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004333// Implements part of 8.12.9 DefineOwnProperty.
4334// There are 3 cases that lead here:
4335// Step 4b - define a new accessor property.
4336// Steps 9c & 12 - replace an existing data property with an accessor property.
4337// Step 12 - update an existing accessor property with an accessor or generic
4338// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004339RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004342 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004343 RUNTIME_ASSERT(!obj->IsNull());
4344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4345 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4346 RUNTIME_ASSERT(IsValidAccessor(getter));
4347 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4348 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004349 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004352
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004353 // TODO(svenpanne) Define getter/setter/attributes in a single step.
4354 if (getter->IsNull() && setter->IsNull()) {
4355 JSArray* array;
4356 { MaybeObject* maybe_array = GetOwnProperty(isolate, obj, name);
4357 if (!maybe_array->To(&array)) return maybe_array;
4358 }
4359 Object* current = FixedArray::cast(array->elements())->get(GETTER_INDEX);
4360 getter = Handle<Object>(current, isolate);
4361 }
4362 if (!getter->IsNull()) {
4363 MaybeObject* ok =
4364 obj->DefineAccessor(*name, ACCESSOR_GETTER, *getter, attr);
4365 if (ok->IsFailure()) return ok;
4366 }
4367 if (!setter->IsNull()) {
4368 MaybeObject* ok =
4369 obj->DefineAccessor(*name, ACCESSOR_SETTER, *setter, attr);
4370 if (ok->IsFailure()) return ok;
4371 }
4372
4373 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004374}
4375
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004376// Implements part of 8.12.9 DefineOwnProperty.
4377// There are 3 cases that lead here:
4378// Step 4a - define a new data property.
4379// Steps 9b & 12 - replace an existing accessor property with a data property.
4380// Step 12 - update an existing data property with a data or generic
4381// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004382RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004383 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004384 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004385 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4386 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004387 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004388 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004389 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004390 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4391
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004392 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004393 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004394
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004395 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004396 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004397 Object* callback = result.GetCallbackObject();
4398 // To be compatible with Safari we do not change the value on API objects
4399 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4400 // the value.
4401 if (callback->IsAccessorInfo()) {
4402 return isolate->heap()->undefined_value();
4403 }
4404 // Avoid redefining foreign callback as data property, just use the stored
4405 // setter to update the value instead.
4406 // TODO(mstarzinger): So far this only works if property attributes don't
4407 // change, this should be fixed once we cleanup the underlying code.
4408 if (callback->IsForeign() && result.GetAttributes() == attr) {
4409 return js_object->SetPropertyWithCallback(callback,
4410 *name,
4411 *obj_value,
4412 result.holder(),
4413 kStrictMode);
4414 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004415 }
4416
ager@chromium.org5c838252010-02-19 08:53:10 +00004417 // Take special care when attributes are different and there is already
4418 // a property. For simplicity we normalize the property which enables us
4419 // to not worry about changing the instance_descriptor and creating a new
4420 // map. The current version of SetObjectProperty does not handle attributes
4421 // correctly in the case where a property is a field and is reset with
4422 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004423 if (result.IsProperty() &&
4424 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004425 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004426 if (js_object->IsJSGlobalProxy()) {
4427 // Since the result is a property, the prototype will exist so
4428 // we don't have to check for null.
4429 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004430 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004431 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004432 // Use IgnoreAttributes version since a readonly property may be
4433 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004434 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4435 *obj_value,
4436 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004437 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004439 return Runtime::ForceSetObjectProperty(isolate,
4440 js_object,
4441 name,
4442 obj_value,
4443 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004444}
4445
4446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4448 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004449 Handle<Object> key,
4450 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004451 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004452 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004453 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004455
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004457 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004459 isolate->factory()->NewTypeError("non_object_property_store",
4460 HandleVector(args, 2));
4461 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004462 }
4463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004464 if (object->IsJSProxy()) {
4465 bool has_pending_exception = false;
4466 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4467 if (has_pending_exception) return Failure::Exception();
4468 return JSProxy::cast(*object)->SetProperty(
4469 String::cast(*name), *value, attr, strict_mode);
4470 }
4471
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 // If the object isn't a JavaScript object, we ignore the store.
4473 if (!object->IsJSObject()) return *value;
4474
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004475 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4476
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 // Check if the given key is an array index.
4478 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004479 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4481 // of a string using [] notation. We need to support this too in
4482 // JavaScript.
4483 // In the case of a String object we just need to redirect the assignment to
4484 // the underlying string if the index is in range. Since the underlying
4485 // string does nothing with the assignment then we can ignore such
4486 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004487 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004489 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004491 Handle<Object> result = JSObject::SetElement(
4492 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004493 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494 return *value;
4495 }
4496
4497 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004498 Handle<Object> result;
4499 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004500 result = JSObject::SetElement(
4501 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004503 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004504 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004505 result = JSReceiver::SetProperty(
4506 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004508 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509 return *value;
4510 }
4511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 bool has_pending_exception = false;
4514 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4515 if (has_pending_exception) return Failure::Exception();
4516 Handle<String> name = Handle<String>::cast(converted);
4517
4518 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004519 return js_object->SetElement(
4520 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004522 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523 }
4524}
4525
4526
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004527MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4528 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004529 Handle<Object> key,
4530 Handle<Object> value,
4531 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004532 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533
4534 // Check if the given key is an array index.
4535 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004536 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004537 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4538 // of a string using [] notation. We need to support this too in
4539 // JavaScript.
4540 // In the case of a String object we just need to redirect the assignment to
4541 // the underlying string if the index is in range. Since the underlying
4542 // string does nothing with the assignment then we can ignore such
4543 // assignments.
4544 if (js_object->IsStringObjectWithCharacterAt(index)) {
4545 return *value;
4546 }
4547
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004548 return js_object->SetElement(
4549 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004550 }
4551
4552 if (key->IsString()) {
4553 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004554 return js_object->SetElement(
4555 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004556 } else {
4557 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004558 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004559 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4560 *value,
4561 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004562 }
4563 }
4564
4565 // Call-back into JavaScript to convert the key to a string.
4566 bool has_pending_exception = false;
4567 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4568 if (has_pending_exception) return Failure::Exception();
4569 Handle<String> name = Handle<String>::cast(converted);
4570
4571 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004572 return js_object->SetElement(
4573 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004574 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004575 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004576 }
4577}
4578
4579
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004580MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004581 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004582 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004584
4585 // Check if the given key is an array index.
4586 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004587 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004588 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4589 // characters of a string using [] notation. In the case of a
4590 // String object we just need to redirect the deletion to the
4591 // underlying string if the index is in range. Since the
4592 // underlying string does nothing with the deletion, we can ignore
4593 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004594 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004595 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004596 }
4597
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004598 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004599 }
4600
4601 Handle<String> key_string;
4602 if (key->IsString()) {
4603 key_string = Handle<String>::cast(key);
4604 } else {
4605 // Call-back into JavaScript to convert the key to a string.
4606 bool has_pending_exception = false;
4607 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4608 if (has_pending_exception) return Failure::Exception();
4609 key_string = Handle<String>::cast(converted);
4610 }
4611
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004612 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004613 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004614}
4615
4616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004617RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004619 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004620
4621 Handle<Object> object = args.at<Object>(0);
4622 Handle<Object> key = args.at<Object>(1);
4623 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004624 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004625 RUNTIME_ASSERT(
4626 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004628 PropertyAttributes attributes =
4629 static_cast<PropertyAttributes>(unchecked_attributes);
4630
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004631 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004632 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004633 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004634 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004636
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 return Runtime::SetObjectProperty(isolate,
4638 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004639 key,
4640 value,
4641 attributes,
4642 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643}
4644
4645
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004646RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4647 NoHandleAllocation ha;
4648 RUNTIME_ASSERT(args.length() == 1);
4649 Handle<Object> object = args.at<Object>(0);
4650 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4651}
4652
4653
4654RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4655 NoHandleAllocation ha;
4656 RUNTIME_ASSERT(args.length() == 1);
4657 Handle<Object> object = args.at<Object>(0);
4658 return TransitionElements(object, FAST_ELEMENTS, isolate);
4659}
4660
4661
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004662// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004663// This is used to decide if we should transform null and undefined
4664// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004665RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004666 NoHandleAllocation ha;
4667 RUNTIME_ASSERT(args.length() == 1);
4668
4669 Handle<Object> object = args.at<Object>(0);
4670
4671 if (object->IsJSFunction()) {
4672 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004673 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004674 }
4675 return isolate->heap()->undefined_value();
4676}
4677
4678
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004679RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4680 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004681 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004682 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4683 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004684 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004685 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4686 HandleScope scope;
4687
4688 Object* raw_boilerplate_object = literals->get(literal_index);
4689 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4690#if DEBUG
4691 ElementsKind elements_kind = object->GetElementsKind();
4692#endif
4693 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4694 // Smis should never trigger transitions.
4695 ASSERT(!value->IsSmi());
4696
4697 if (value->IsNumber()) {
4698 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004699 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4700 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004701 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4702 FixedDoubleArray* double_array =
4703 FixedDoubleArray::cast(object->elements());
4704 HeapNumber* number = HeapNumber::cast(*value);
4705 double_array->set(store_index, number->Number());
4706 } else {
4707 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4708 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004709 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4710 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004711 FixedArray* object_array =
4712 FixedArray::cast(object->elements());
4713 object_array->set(store_index, *value);
4714 }
4715 return *object;
4716}
4717
4718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719// Set a local property, even if it is READ_ONLY. If the property does not
4720// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004721RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004723 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004724 CONVERT_ARG_CHECKED(JSObject, object, 0);
4725 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004726 // Compute attributes.
4727 PropertyAttributes attributes = NONE;
4728 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004729 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004730 // Only attribute bits should be set.
4731 RUNTIME_ASSERT(
4732 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4733 attributes = static_cast<PropertyAttributes>(unchecked_value);
4734 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004736 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004737 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004738}
4739
4740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004743 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004745 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4746 CONVERT_ARG_CHECKED(String, key, 1);
4747 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004748 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004749 ? JSReceiver::STRICT_DELETION
4750 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751}
4752
4753
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004754static Object* HasLocalPropertyImplementation(Isolate* isolate,
4755 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004756 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004757 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004758 // Handle hidden prototypes. If there's a hidden prototype above this thing
4759 // then we have to check it for properties, because they are supposed to
4760 // look like they are on this object.
4761 Handle<Object> proto(object->GetPrototype());
4762 if (proto->IsJSObject() &&
4763 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004764 return HasLocalPropertyImplementation(isolate,
4765 Handle<JSObject>::cast(proto),
4766 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004767 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004769}
4770
4771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004772RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773 NoHandleAllocation ha;
4774 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004775 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004777 uint32_t index;
4778 const bool key_is_array_index = key->AsArrayIndex(&index);
4779
ager@chromium.org9085a012009-05-11 19:22:57 +00004780 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004782 if (obj->IsJSObject()) {
4783 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004784 // Fast case: either the key is a real named property or it is not
4785 // an array index and there are no interceptors or hidden
4786 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004787 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004788 Map* map = object->map();
4789 if (!key_is_array_index &&
4790 !map->has_named_interceptor() &&
4791 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4792 return isolate->heap()->false_value();
4793 }
4794 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 HandleScope scope(isolate);
4796 return HasLocalPropertyImplementation(isolate,
4797 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004798 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004799 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004801 String* string = String::cast(obj);
4802 if (index < static_cast<uint32_t>(string->length())) {
4803 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004804 }
4805 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004806 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807}
4808
4809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004810RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 NoHandleAllocation na;
4812 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004813 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4814 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004816 bool result = receiver->HasProperty(key);
4817 if (isolate->has_pending_exception()) return Failure::Exception();
4818 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819}
4820
4821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004822RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 NoHandleAllocation na;
4824 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004825 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4826 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004828 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004829 if (isolate->has_pending_exception()) return Failure::Exception();
4830 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831}
4832
4833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004834RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 NoHandleAllocation ha;
4836 ASSERT(args.length() == 2);
4837
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004838 CONVERT_ARG_CHECKED(JSObject, object, 0);
4839 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840
4841 uint32_t index;
4842 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004843 JSObject::LocalElementType type = object->HasLocalElement(index);
4844 switch (type) {
4845 case JSObject::UNDEFINED_ELEMENT:
4846 case JSObject::STRING_CHARACTER_ELEMENT:
4847 return isolate->heap()->false_value();
4848 case JSObject::INTERCEPTED_ELEMENT:
4849 case JSObject::FAST_ELEMENT:
4850 return isolate->heap()->true_value();
4851 case JSObject::DICTIONARY_ELEMENT: {
4852 if (object->IsJSGlobalProxy()) {
4853 Object* proto = object->GetPrototype();
4854 if (proto->IsNull()) {
4855 return isolate->heap()->false_value();
4856 }
4857 ASSERT(proto->IsJSGlobalObject());
4858 object = JSObject::cast(proto);
4859 }
4860 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004861 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004862 if (elements->map() ==
4863 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004864 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004865 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004866 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004867 }
4868 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004869 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004870 PropertyDetails details = dictionary->DetailsAt(entry);
4871 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4872 }
4873 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 }
4875
ager@chromium.org870a0b62008-11-04 11:43:05 +00004876 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004877 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878}
4879
4880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004881RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004882 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004883 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004884 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004885 bool threw = false;
4886 Handle<JSArray> result = GetKeysFor(object, &threw);
4887 if (threw) return Failure::Exception();
4888 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889}
4890
4891
4892// Returns either a FixedArray as Runtime_GetPropertyNames,
4893// or, if the given object has an enum cache that contains
4894// all enumerable properties of the object and its prototypes
4895// have none, the map of the object. This is used to speed up
4896// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004897RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898 ASSERT(args.length() == 1);
4899
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004900 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901
4902 if (raw_object->IsSimpleEnum()) return raw_object->map();
4903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004904 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004905 Handle<JSReceiver> object(raw_object);
4906 bool threw = false;
4907 Handle<FixedArray> content =
4908 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4909 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004910
4911 // Test again, since cache may have been built by preceding call.
4912 if (object->IsSimpleEnum()) return object->map();
4913
4914 return *content;
4915}
4916
4917
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004918// Find the length of the prototype chain that is to to handled as one. If a
4919// prototype object is hidden it is to be viewed as part of the the object it
4920// is prototype for.
4921static int LocalPrototypeChainLength(JSObject* obj) {
4922 int count = 1;
4923 Object* proto = obj->GetPrototype();
4924 while (proto->IsJSObject() &&
4925 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4926 count++;
4927 proto = JSObject::cast(proto)->GetPrototype();
4928 }
4929 return count;
4930}
4931
4932
4933// Return the names of the local named properties.
4934// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004935RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004936 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004937 ASSERT(args.length() == 1);
4938 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004939 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004940 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004941 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004942
4943 // Skip the global proxy as it has no properties and always delegates to the
4944 // real global object.
4945 if (obj->IsJSGlobalProxy()) {
4946 // Only collect names if access is permitted.
4947 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 !isolate->MayNamedAccess(*obj,
4949 isolate->heap()->undefined_value(),
4950 v8::ACCESS_KEYS)) {
4951 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4952 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004953 }
4954 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4955 }
4956
4957 // Find the number of objects making up this.
4958 int length = LocalPrototypeChainLength(*obj);
4959
4960 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004961 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004962 int total_property_count = 0;
4963 Handle<JSObject> jsproto = obj;
4964 for (int i = 0; i < length; i++) {
4965 // Only collect names if access is permitted.
4966 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 !isolate->MayNamedAccess(*jsproto,
4968 isolate->heap()->undefined_value(),
4969 v8::ACCESS_KEYS)) {
4970 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4971 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004972 }
4973 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004974 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004975 local_property_count[i] = n;
4976 total_property_count += n;
4977 if (i < length - 1) {
4978 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4979 }
4980 }
4981
4982 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004983 Handle<FixedArray> names =
4984 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985
4986 // Get the property names.
4987 jsproto = obj;
4988 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004989 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004990 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004991 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4992 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004993 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994 proto_with_hidden_properties++;
4995 }
4996 if (i < length - 1) {
4997 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4998 }
4999 }
5000
5001 // Filter out name of hidden propeties object.
5002 if (proto_with_hidden_properties > 0) {
5003 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005005 names->length() - proto_with_hidden_properties);
5006 int dest_pos = 0;
5007 for (int i = 0; i < total_property_count; i++) {
5008 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005010 continue;
5011 }
5012 names->set(dest_pos++, name);
5013 }
5014 }
5015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017}
5018
5019
5020// Return the names of the local indexed properties.
5021// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005023 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005024 ASSERT(args.length() == 1);
5025 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005026 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005027 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005028 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029
5030 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005033 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005034}
5035
5036
5037// Return information on whether an object has a named or indexed interceptor.
5038// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005039RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005041 ASSERT(args.length() == 1);
5042 if (!args[0]->IsJSObject()) {
5043 return Smi::FromInt(0);
5044 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005045 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046
5047 int result = 0;
5048 if (obj->HasNamedInterceptor()) result |= 2;
5049 if (obj->HasIndexedInterceptor()) result |= 1;
5050
5051 return Smi::FromInt(result);
5052}
5053
5054
5055// Return property names from named interceptor.
5056// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005057RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005058 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005059 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005060 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005061
5062 if (obj->HasNamedInterceptor()) {
5063 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5064 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005067}
5068
5069
5070// Return element names from indexed interceptor.
5071// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005072RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005074 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005075 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005076
5077 if (obj->HasIndexedInterceptor()) {
5078 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5079 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5080 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005082}
5083
5084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005085RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005086 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005087 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005089 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005090
5091 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005092 // Do access checks before going to the global object.
5093 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005095 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005096 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5097 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005098 }
5099
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005100 Handle<Object> proto(object->GetPrototype());
5101 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005103 object = Handle<JSObject>::cast(proto);
5104 }
5105
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005106 bool threw = false;
5107 Handle<FixedArray> contents =
5108 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5109 if (threw) return Failure::Exception();
5110
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005111 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5112 // property array and since the result is mutable we have to create
5113 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005114 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005115 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005116 for (int i = 0; i < length; i++) {
5117 Object* entry = contents->get(i);
5118 if (entry->IsString()) {
5119 copy->set(i, entry);
5120 } else {
5121 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 HandleScope scope(isolate);
5123 Handle<Object> entry_handle(entry, isolate);
5124 Handle<Object> entry_str =
5125 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005126 copy->set(i, *entry_str);
5127 }
5128 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005129 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005130}
5131
5132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005133RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005134 NoHandleAllocation ha;
5135 ASSERT(args.length() == 1);
5136
5137 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005138 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005139 it.AdvanceToArgumentsFrame();
5140 JavaScriptFrame* frame = it.frame();
5141
5142 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005143 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005144
5145 // Try to convert the key to an index. If successful and within
5146 // index return the the argument from the frame.
5147 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005148 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149 return frame->GetParameter(index);
5150 }
5151
5152 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005154 bool exception = false;
5155 Handle<Object> converted =
5156 Execution::ToString(args.at<Object>(0), &exception);
5157 if (exception) return Failure::Exception();
5158 Handle<String> key = Handle<String>::cast(converted);
5159
5160 // Try to convert the string key into an array index.
5161 if (key->AsArrayIndex(&index)) {
5162 if (index < n) {
5163 return frame->GetParameter(index);
5164 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166 }
5167 }
5168
5169 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005170 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5171 if (key->Equals(isolate->heap()->callee_symbol())) {
5172 Object* function = frame->function();
5173 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005174 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 return isolate->Throw(*isolate->factory()->NewTypeError(
5176 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5177 }
5178 return function;
5179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180
5181 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183}
5184
5185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005186RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005187 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005188 Object* object = args[0];
5189 return (object->IsJSObject() && !object->IsGlobalObject())
5190 ? JSObject::cast(object)->TransformToFastProperties(0)
5191 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005192}
5193
5194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005195RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005196 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005197 Object* obj = args[0];
5198 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5199 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5200 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005201}
5202
5203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005204RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 NoHandleAllocation ha;
5206 ASSERT(args.length() == 1);
5207
5208 return args[0]->ToBoolean();
5209}
5210
5211
5212// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5213// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005214RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215 NoHandleAllocation ha;
5216
5217 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005218 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005219 HeapObject* heap_obj = HeapObject::cast(obj);
5220
5221 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 if (heap_obj->map()->is_undetectable()) {
5223 return isolate->heap()->undefined_symbol();
5224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225
5226 InstanceType instance_type = heap_obj->map()->instance_type();
5227 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005228 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 }
5230
5231 switch (instance_type) {
5232 case ODDBALL_TYPE:
5233 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005234 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 }
5236 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005237 return FLAG_harmony_typeof
5238 ? isolate->heap()->null_symbol()
5239 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 }
5241 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005242 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005243 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005244 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 default:
5247 // For any kind of object not handled above, the spec rule for
5248 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005249 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005250 }
5251}
5252
5253
lrn@chromium.org25156de2010-04-06 13:10:27 +00005254static bool AreDigits(const char*s, int from, int to) {
5255 for (int i = from; i < to; i++) {
5256 if (s[i] < '0' || s[i] > '9') return false;
5257 }
5258
5259 return true;
5260}
5261
5262
5263static int ParseDecimalInteger(const char*s, int from, int to) {
5264 ASSERT(to - from < 10); // Overflow is not possible.
5265 ASSERT(from < to);
5266 int d = s[from] - '0';
5267
5268 for (int i = from + 1; i < to; i++) {
5269 d = 10 * d + (s[i] - '0');
5270 }
5271
5272 return d;
5273}
5274
5275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005276RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005277 NoHandleAllocation ha;
5278 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005279 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005280 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005281
5282 // Fast case: short integer or some sorts of junk values.
5283 int len = subject->length();
5284 if (subject->IsSeqAsciiString()) {
5285 if (len == 0) return Smi::FromInt(0);
5286
5287 char const* data = SeqAsciiString::cast(subject)->GetChars();
5288 bool minus = (data[0] == '-');
5289 int start_pos = (minus ? 1 : 0);
5290
5291 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005292 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005293 } else if (data[start_pos] > '9') {
5294 // Fast check for a junk value. A valid string may start from a
5295 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5296 // the 'I' character ('Infinity'). All of that have codes not greater than
5297 // '9' except 'I'.
5298 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005299 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005300 }
5301 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5302 // The maximal/minimal smi has 10 digits. If the string has less digits we
5303 // know it will fit into the smi-data type.
5304 int d = ParseDecimalInteger(data, start_pos, len);
5305 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005306 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005307 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005308 } else if (!subject->HasHashCode() &&
5309 len <= String::kMaxArrayIndexSize &&
5310 (len == 1 || data[0] != '0')) {
5311 // String hash is not calculated yet but all the data are present.
5312 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005313 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005314#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005315 subject->Hash(); // Force hash calculation.
5316 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5317 static_cast<int>(hash));
5318#endif
5319 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005320 }
5321 return Smi::FromInt(d);
5322 }
5323 }
5324
5325 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005326 return isolate->heap()->NumberFromDouble(
5327 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005328}
5329
5330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005331RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005332 NoHandleAllocation ha;
5333 ASSERT(args.length() == 1);
5334
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005335 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 int length = Smi::cast(codes->length())->value();
5337
5338 // Check if the string can be ASCII.
5339 int i;
5340 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005341 Object* element;
5342 { MaybeObject* maybe_element = codes->GetElement(i);
5343 // We probably can't get an exception here, but just in order to enforce
5344 // the checking of inputs in the runtime calls we check here.
5345 if (!maybe_element->ToObject(&element)) return maybe_element;
5346 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005347 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5348 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5349 break;
5350 }
5351
lrn@chromium.org303ada72010-10-27 09:33:13 +00005352 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005353 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005354 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005356 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357 }
5358
lrn@chromium.org303ada72010-10-27 09:33:13 +00005359 Object* object = NULL;
5360 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005361 String* result = String::cast(object);
5362 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005363 Object* element;
5364 { MaybeObject* maybe_element = codes->GetElement(i);
5365 if (!maybe_element->ToObject(&element)) return maybe_element;
5366 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005368 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369 }
5370 return result;
5371}
5372
5373
5374// kNotEscaped is generated by the following:
5375//
5376// #!/bin/perl
5377// for (my $i = 0; $i < 256; $i++) {
5378// print "\n" if $i % 16 == 0;
5379// my $c = chr($i);
5380// my $escaped = 1;
5381// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5382// print $escaped ? "0, " : "1, ";
5383// }
5384
5385
5386static bool IsNotEscaped(uint16_t character) {
5387 // Only for 8 bit characters, the rest are always escaped (in a different way)
5388 ASSERT(character < 256);
5389 static const char kNotEscaped[256] = {
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, 1, 1, 0, 1, 1, 1,
5393 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5394 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5395 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5396 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5397 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5399 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5400 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5404 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5406 };
5407 return kNotEscaped[character] != 0;
5408}
5409
5410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005411RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 const char hex_chars[] = "0123456789ABCDEF";
5413 NoHandleAllocation ha;
5414 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005415 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418
5419 int escaped_length = 0;
5420 int length = source->length();
5421 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 Access<StringInputBuffer> buffer(
5423 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 buffer->Reset(source);
5425 while (buffer->has_more()) {
5426 uint16_t character = buffer->GetNext();
5427 if (character >= 256) {
5428 escaped_length += 6;
5429 } else if (IsNotEscaped(character)) {
5430 escaped_length++;
5431 } else {
5432 escaped_length += 3;
5433 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005434 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005435 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005436 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005438 return Failure::OutOfMemoryException();
5439 }
5440 }
5441 }
5442 // No length change implies no change. Return original string if no change.
5443 if (escaped_length == length) {
5444 return source;
5445 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005446 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005447 { MaybeObject* maybe_o =
5448 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005449 if (!maybe_o->ToObject(&o)) return maybe_o;
5450 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 String* destination = String::cast(o);
5452 int dest_position = 0;
5453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 Access<StringInputBuffer> buffer(
5455 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 buffer->Rewind();
5457 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005458 uint16_t chr = buffer->GetNext();
5459 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005460 destination->Set(dest_position, '%');
5461 destination->Set(dest_position+1, 'u');
5462 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5463 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5464 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5465 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005467 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469 dest_position++;
5470 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005471 destination->Set(dest_position, '%');
5472 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5473 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 dest_position += 3;
5475 }
5476 }
5477 return destination;
5478}
5479
5480
5481static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5482 static const signed char kHexValue['g'] = {
5483 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5484 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5485 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5486 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5487 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5488 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5489 -1, 10, 11, 12, 13, 14, 15 };
5490
5491 if (character1 > 'f') return -1;
5492 int hi = kHexValue[character1];
5493 if (hi == -1) return -1;
5494 if (character2 > 'f') return -1;
5495 int lo = kHexValue[character2];
5496 if (lo == -1) return -1;
5497 return (hi << 4) + lo;
5498}
5499
5500
ager@chromium.org870a0b62008-11-04 11:43:05 +00005501static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005502 int i,
5503 int length,
5504 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005505 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005506 int32_t hi = 0;
5507 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508 if (character == '%' &&
5509 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005510 source->Get(i + 1) == 'u' &&
5511 (hi = TwoDigitHex(source->Get(i + 2),
5512 source->Get(i + 3))) != -1 &&
5513 (lo = TwoDigitHex(source->Get(i + 4),
5514 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 *step = 6;
5516 return (hi << 8) + lo;
5517 } else if (character == '%' &&
5518 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005519 (lo = TwoDigitHex(source->Get(i + 1),
5520 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521 *step = 3;
5522 return lo;
5523 } else {
5524 *step = 1;
5525 return character;
5526 }
5527}
5528
5529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005530RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 NoHandleAllocation ha;
5532 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005533 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005535 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536
5537 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005538 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005539
5540 int unescaped_length = 0;
5541 for (int i = 0; i < length; unescaped_length++) {
5542 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005543 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546 i += step;
5547 }
5548
5549 // No length change implies no change. Return original string if no change.
5550 if (unescaped_length == length)
5551 return source;
5552
lrn@chromium.org303ada72010-10-27 09:33:13 +00005553 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005554 { MaybeObject* maybe_o =
5555 ascii ?
5556 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5557 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005558 if (!maybe_o->ToObject(&o)) return maybe_o;
5559 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 String* destination = String::cast(o);
5561
5562 int dest_position = 0;
5563 for (int i = 0; i < length; dest_position++) {
5564 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005565 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566 i += step;
5567 }
5568 return destination;
5569}
5570
5571
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005572static const unsigned int kQuoteTableLength = 128u;
5573
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005574static const int kJsonQuotesCharactersPerEntry = 8;
5575static const char* const JsonQuotes =
5576 "\\u0000 \\u0001 \\u0002 \\u0003 "
5577 "\\u0004 \\u0005 \\u0006 \\u0007 "
5578 "\\b \\t \\n \\u000b "
5579 "\\f \\r \\u000e \\u000f "
5580 "\\u0010 \\u0011 \\u0012 \\u0013 "
5581 "\\u0014 \\u0015 \\u0016 \\u0017 "
5582 "\\u0018 \\u0019 \\u001a \\u001b "
5583 "\\u001c \\u001d \\u001e \\u001f "
5584 " ! \\\" # "
5585 "$ % & ' "
5586 "( ) * + "
5587 ", - . / "
5588 "0 1 2 3 "
5589 "4 5 6 7 "
5590 "8 9 : ; "
5591 "< = > ? "
5592 "@ A B C "
5593 "D E F G "
5594 "H I J K "
5595 "L M N O "
5596 "P Q R S "
5597 "T U V W "
5598 "X Y Z [ "
5599 "\\\\ ] ^ _ "
5600 "` a b c "
5601 "d e f g "
5602 "h i j k "
5603 "l m n o "
5604 "p q r s "
5605 "t u v w "
5606 "x y z { "
5607 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005608
5609
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005610// For a string that is less than 32k characters it should always be
5611// possible to allocate it in new space.
5612static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5613
5614
5615// Doing JSON quoting cannot make the string more than this many times larger.
5616static const int kJsonQuoteWorstCaseBlowup = 6;
5617
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005618static const int kSpaceForQuotesAndComma = 3;
5619static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005620
5621// Covers the entire ASCII range (all other characters are unchanged by JSON
5622// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005623static const byte JsonQuoteLengths[kQuoteTableLength] = {
5624 6, 6, 6, 6, 6, 6, 6, 6,
5625 2, 2, 2, 6, 2, 2, 6, 6,
5626 6, 6, 6, 6, 6, 6, 6, 6,
5627 6, 6, 6, 6, 6, 6, 6, 6,
5628 1, 1, 2, 1, 1, 1, 1, 1,
5629 1, 1, 1, 1, 1, 1, 1, 1,
5630 1, 1, 1, 1, 1, 1, 1, 1,
5631 1, 1, 1, 1, 1, 1, 1, 1,
5632 1, 1, 1, 1, 1, 1, 1, 1,
5633 1, 1, 1, 1, 1, 1, 1, 1,
5634 1, 1, 1, 1, 1, 1, 1, 1,
5635 1, 1, 1, 1, 2, 1, 1, 1,
5636 1, 1, 1, 1, 1, 1, 1, 1,
5637 1, 1, 1, 1, 1, 1, 1, 1,
5638 1, 1, 1, 1, 1, 1, 1, 1,
5639 1, 1, 1, 1, 1, 1, 1, 1,
5640};
5641
5642
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005643template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005644MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645
5646
5647template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005648MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5649 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005650}
5651
5652
5653template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005654MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5655 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005656}
5657
5658
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005659template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005660static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5661 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005663 const Char* read_cursor = characters.start();
5664 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005665 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005666 int quoted_length = kSpaceForQuotes;
5667 while (read_cursor < end) {
5668 Char c = *(read_cursor++);
5669 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5670 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005671 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005672 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005673 }
5674 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005675 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5676 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005677 Object* new_object;
5678 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005679 return new_alloc;
5680 }
5681 StringType* new_string = StringType::cast(new_object);
5682
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005683 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005684 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005685 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005686 *(write_cursor++) = '"';
5687
5688 read_cursor = characters.start();
5689 while (read_cursor < end) {
5690 Char c = *(read_cursor++);
5691 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5692 *(write_cursor++) = c;
5693 } else {
5694 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5695 const char* replacement = JsonQuotes +
5696 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5697 for (int i = 0; i < len; i++) {
5698 *write_cursor++ = *replacement++;
5699 }
5700 }
5701 }
5702 *(write_cursor++) = '"';
5703 return new_string;
5704}
5705
5706
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005707template <typename SinkChar, typename SourceChar>
5708static inline SinkChar* WriteQuoteJsonString(
5709 Isolate* isolate,
5710 SinkChar* write_cursor,
5711 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005712 // SinkChar is only char if SourceChar is guaranteed to be char.
5713 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005714 const SourceChar* read_cursor = characters.start();
5715 const SourceChar* end = read_cursor + characters.length();
5716 *(write_cursor++) = '"';
5717 while (read_cursor < end) {
5718 SourceChar c = *(read_cursor++);
5719 if (sizeof(SourceChar) > 1u &&
5720 static_cast<unsigned>(c) >= kQuoteTableLength) {
5721 *(write_cursor++) = static_cast<SinkChar>(c);
5722 } else {
5723 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5724 const char* replacement = JsonQuotes +
5725 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5726 write_cursor[0] = replacement[0];
5727 if (len > 1) {
5728 write_cursor[1] = replacement[1];
5729 if (len > 2) {
5730 ASSERT(len == 6);
5731 write_cursor[2] = replacement[2];
5732 write_cursor[3] = replacement[3];
5733 write_cursor[4] = replacement[4];
5734 write_cursor[5] = replacement[5];
5735 }
5736 }
5737 write_cursor += len;
5738 }
5739 }
5740 *(write_cursor++) = '"';
5741 return write_cursor;
5742}
5743
5744
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005745template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746static MaybeObject* QuoteJsonString(Isolate* isolate,
5747 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005748 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005749 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005750 int worst_case_length =
5751 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005752 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005754 }
5755
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005756 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5757 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005758 Object* new_object;
5759 if (!new_alloc->ToObject(&new_object)) {
5760 return new_alloc;
5761 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005763 // Even if our string is small enough to fit in new space we still have to
5764 // handle it being allocated in old space as may happen in the third
5765 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5766 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005767 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005768 }
5769 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005770 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005771
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005772 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005773 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005774 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005775 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5776 write_cursor,
5777 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005778 int final_length = static_cast<int>(
5779 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005780 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005781 isolate->heap()->new_space()->
5782 template ShrinkStringAtAllocationBoundary<StringType>(
5783 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005784 return new_string;
5785}
5786
5787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005788RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005789 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005790 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005791 if (!str->IsFlat()) {
5792 MaybeObject* try_flatten = str->TryFlatten();
5793 Object* flat;
5794 if (!try_flatten->ToObject(&flat)) {
5795 return try_flatten;
5796 }
5797 str = String::cast(flat);
5798 ASSERT(str->IsFlat());
5799 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005800 String::FlatContent flat = str->GetFlatContent();
5801 ASSERT(flat.IsFlat());
5802 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005803 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005804 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005805 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005807 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005808 }
5809}
5810
5811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005812RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005813 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005814 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005815 if (!str->IsFlat()) {
5816 MaybeObject* try_flatten = str->TryFlatten();
5817 Object* flat;
5818 if (!try_flatten->ToObject(&flat)) {
5819 return try_flatten;
5820 }
5821 str = String::cast(flat);
5822 ASSERT(str->IsFlat());
5823 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005824 String::FlatContent flat = str->GetFlatContent();
5825 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005827 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005828 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005830 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005831 }
5832}
5833
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005834
5835template <typename Char, typename StringType>
5836static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5837 FixedArray* array,
5838 int worst_case_length) {
5839 int length = array->length();
5840
5841 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5842 worst_case_length);
5843 Object* new_object;
5844 if (!new_alloc->ToObject(&new_object)) {
5845 return new_alloc;
5846 }
5847 if (!isolate->heap()->new_space()->Contains(new_object)) {
5848 // Even if our string is small enough to fit in new space we still have to
5849 // handle it being allocated in old space as may happen in the third
5850 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5851 // CEntryStub::GenerateCore.
5852 return isolate->heap()->undefined_value();
5853 }
5854 AssertNoAllocation no_gc;
5855 StringType* new_string = StringType::cast(new_object);
5856 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5857
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005858 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005859 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005860 *(write_cursor++) = '[';
5861 for (int i = 0; i < length; i++) {
5862 if (i != 0) *(write_cursor++) = ',';
5863 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005864 String::FlatContent content = str->GetFlatContent();
5865 ASSERT(content.IsFlat());
5866 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005867 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5868 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005869 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005870 } else {
5871 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5872 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005873 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005874 }
5875 }
5876 *(write_cursor++) = ']';
5877
5878 int final_length = static_cast<int>(
5879 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005880 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005881 isolate->heap()->new_space()->
5882 template ShrinkStringAtAllocationBoundary<StringType>(
5883 new_string, final_length);
5884 return new_string;
5885}
5886
5887
5888RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5889 NoHandleAllocation ha;
5890 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005891 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005892
5893 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5894 FixedArray* elements = FixedArray::cast(array->elements());
5895 int n = elements->length();
5896 bool ascii = true;
5897 int total_length = 0;
5898
5899 for (int i = 0; i < n; i++) {
5900 Object* elt = elements->get(i);
5901 if (!elt->IsString()) return isolate->heap()->undefined_value();
5902 String* element = String::cast(elt);
5903 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5904 total_length += element->length();
5905 if (ascii && element->IsTwoByteRepresentation()) {
5906 ascii = false;
5907 }
5908 }
5909
5910 int worst_case_length =
5911 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5912 + total_length * kJsonQuoteWorstCaseBlowup;
5913
5914 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5915 return isolate->heap()->undefined_value();
5916 }
5917
5918 if (ascii) {
5919 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5920 elements,
5921 worst_case_length);
5922 } else {
5923 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5924 elements,
5925 worst_case_length);
5926 }
5927}
5928
5929
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005930RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 NoHandleAllocation ha;
5932
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005933 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005934 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005936 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937
lrn@chromium.org25156de2010-04-06 13:10:27 +00005938 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005939 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941}
5942
5943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005944RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005946 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947
5948 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005949 double value = StringToDouble(isolate->unicode_cache(),
5950 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951
5952 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005953 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954}
5955
5956
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005959 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005960 String* s,
5961 int length,
5962 int input_string_length,
5963 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005964 // We try this twice, once with the assumption that the result is no longer
5965 // than the input and, if that assumption breaks, again with the exact
5966 // length. This may not be pretty, but it is nicer than what was here before
5967 // and I hereby claim my vaffel-is.
5968 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 // Allocate the resulting string.
5970 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005971 // NOTE: This assumes that the upper/lower case of an ASCII
5972 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 // might break in the future if we implement more context and locale
5974 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005975 Object* o;
5976 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005977 ? isolate->heap()->AllocateRawAsciiString(length)
5978 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005979 if (!maybe_o->ToObject(&o)) return maybe_o;
5980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 String* result = String::cast(o);
5982 bool has_changed_character = false;
5983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 // Convert all characters to upper case, assuming that they will fit
5985 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986 Access<StringInputBuffer> buffer(
5987 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005989 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 // We can assume that the string is not empty
5991 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005992 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005993 bool has_next = buffer->has_more();
5994 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 int char_length = mapping->get(current, next, chars);
5996 if (char_length == 0) {
5997 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005998 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 i++;
6000 } else if (char_length == 1) {
6001 // Common case: converting the letter resulted in one character.
6002 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006003 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 has_changed_character = true;
6005 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006006 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 // We've assumed that the result would be as long as the
6008 // input but here is a character that converts to several
6009 // characters. No matter, we calculate the exact length
6010 // of the result and try the whole thing again.
6011 //
6012 // Note that this leaves room for optimization. We could just
6013 // memcpy what we already have to the result string. Also,
6014 // the result string is the last object allocated we could
6015 // "realloc" it and probably, in the vast majority of cases,
6016 // extend the existing string to be able to hold the full
6017 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006018 int next_length = 0;
6019 if (has_next) {
6020 next_length = mapping->get(next, 0, chars);
6021 if (next_length == 0) next_length = 1;
6022 }
6023 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 while (buffer->has_more()) {
6025 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006026 // NOTE: we use 0 as the next character here because, while
6027 // the next character may affect what a character converts to,
6028 // it does not in any case affect the length of what it convert
6029 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 int char_length = mapping->get(current, 0, chars);
6031 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006032 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006034 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006035 return Failure::OutOfMemoryException();
6036 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006038 // Try again with the real length.
6039 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 } else {
6041 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006042 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043 i++;
6044 }
6045 has_changed_character = true;
6046 }
6047 current = next;
6048 }
6049 if (has_changed_character) {
6050 return result;
6051 } else {
6052 // If we didn't actually change anything in doing the conversion
6053 // we simple return the result and let the converted string
6054 // become garbage; there is no reason to keep two identical strings
6055 // alive.
6056 return s;
6057 }
6058}
6059
6060
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006061namespace {
6062
lrn@chromium.org303ada72010-10-27 09:33:13 +00006063static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6064
6065
6066// Given a word and two range boundaries returns a word with high bit
6067// set in every byte iff the corresponding input byte was strictly in
6068// the range (m, n). All the other bits in the result are cleared.
6069// This function is only useful when it can be inlined and the
6070// boundaries are statically known.
6071// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006072// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006073static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006074 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006075 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6076 // Use strict inequalities since in edge cases the function could be
6077 // further simplified.
6078 ASSERT(0 < m && m < n && n < 0x7F);
6079 // Has high bit set in every w byte less than n.
6080 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6081 // Has high bit set in every w byte greater than m.
6082 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6083 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6084}
6085
6086
6087enum AsciiCaseConversion {
6088 ASCII_TO_LOWER,
6089 ASCII_TO_UPPER
6090};
6091
6092
6093template <AsciiCaseConversion dir>
6094struct FastAsciiConverter {
6095 static bool Convert(char* dst, char* src, int length) {
6096#ifdef DEBUG
6097 char* saved_dst = dst;
6098 char* saved_src = src;
6099#endif
6100 // We rely on the distance between upper and lower case letters
6101 // being a known power of 2.
6102 ASSERT('a' - 'A' == (1 << 5));
6103 // Boundaries for the range of input characters than require conversion.
6104 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6105 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6106 bool changed = false;
6107 char* const limit = src + length;
6108#ifdef V8_HOST_CAN_READ_UNALIGNED
6109 // Process the prefix of the input that requires no conversion one
6110 // (machine) word at a time.
6111 while (src <= limit - sizeof(uintptr_t)) {
6112 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6113 if (AsciiRangeMask(w, lo, hi) != 0) {
6114 changed = true;
6115 break;
6116 }
6117 *reinterpret_cast<uintptr_t*>(dst) = w;
6118 src += sizeof(uintptr_t);
6119 dst += sizeof(uintptr_t);
6120 }
6121 // Process the remainder of the input performing conversion when
6122 // required one word at a time.
6123 while (src <= limit - sizeof(uintptr_t)) {
6124 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6125 uintptr_t m = AsciiRangeMask(w, lo, hi);
6126 // The mask has high (7th) bit set in every byte that needs
6127 // conversion and we know that the distance between cases is
6128 // 1 << 5.
6129 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6130 src += sizeof(uintptr_t);
6131 dst += sizeof(uintptr_t);
6132 }
6133#endif
6134 // Process the last few bytes of the input (or the whole input if
6135 // unaligned access is not supported).
6136 while (src < limit) {
6137 char c = *src;
6138 if (lo < c && c < hi) {
6139 c ^= (1 << 5);
6140 changed = true;
6141 }
6142 *dst = c;
6143 ++src;
6144 ++dst;
6145 }
6146#ifdef DEBUG
6147 CheckConvert(saved_dst, saved_src, length, changed);
6148#endif
6149 return changed;
6150 }
6151
6152#ifdef DEBUG
6153 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6154 bool expected_changed = false;
6155 for (int i = 0; i < length; i++) {
6156 if (dst[i] == src[i]) continue;
6157 expected_changed = true;
6158 if (dir == ASCII_TO_LOWER) {
6159 ASSERT('A' <= src[i] && src[i] <= 'Z');
6160 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6161 } else {
6162 ASSERT(dir == ASCII_TO_UPPER);
6163 ASSERT('a' <= src[i] && src[i] <= 'z');
6164 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6165 }
6166 }
6167 ASSERT(expected_changed == changed);
6168 }
6169#endif
6170};
6171
6172
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006173struct ToLowerTraits {
6174 typedef unibrow::ToLowercase UnibrowConverter;
6175
lrn@chromium.org303ada72010-10-27 09:33:13 +00006176 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006177};
6178
6179
6180struct ToUpperTraits {
6181 typedef unibrow::ToUppercase UnibrowConverter;
6182
lrn@chromium.org303ada72010-10-27 09:33:13 +00006183 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006184};
6185
6186} // namespace
6187
6188
6189template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006190MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006191 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006193 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006194 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006195 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006196 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006197
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006198 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006199 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200 if (length == 0) return s;
6201
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006202 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006203 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006204 // NOTE: This assumes that the upper/lower case of an ASCII
6205 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006206 // might break in the future if we implement more context and locale
6207 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006208 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006211 if (!maybe_o->ToObject(&o)) return maybe_o;
6212 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006213 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006214 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006215 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 return has_changed_character ? result : s;
6217 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218
lrn@chromium.org303ada72010-10-27 09:33:13 +00006219 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006220 { MaybeObject* maybe_answer =
6221 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006222 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6223 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006224 if (answer->IsSmi()) {
6225 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006226 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006227 ConvertCaseHelper(isolate,
6228 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006229 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6230 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006231 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006232 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006233}
6234
6235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006236RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006237 return ConvertCase<ToLowerTraits>(
6238 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239}
6240
6241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006242RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 return ConvertCase<ToUpperTraits>(
6244 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006245}
6246
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006248static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006249 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006250}
6251
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006253RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006254 NoHandleAllocation ha;
6255 ASSERT(args.length() == 3);
6256
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006257 CONVERT_ARG_CHECKED(String, s, 0);
6258 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6259 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006260
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006261 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006262 int length = s->length();
6263
6264 int left = 0;
6265 if (trimLeft) {
6266 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6267 left++;
6268 }
6269 }
6270
6271 int right = length;
6272 if (trimRight) {
6273 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6274 right--;
6275 }
6276 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006277 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006278}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006281RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006282 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006283 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006284 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6285 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006286 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6287
6288 int subject_length = subject->length();
6289 int pattern_length = pattern->length();
6290 RUNTIME_ASSERT(pattern_length > 0);
6291
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006292 if (limit == 0xffffffffu) {
6293 Handle<Object> cached_answer(StringSplitCache::Lookup(
6294 isolate->heap()->string_split_cache(),
6295 *subject,
6296 *pattern));
6297 if (*cached_answer != Smi::FromInt(0)) {
6298 Handle<JSArray> result =
6299 isolate->factory()->NewJSArrayWithElements(
6300 Handle<FixedArray>::cast(cached_answer));
6301 return *result;
6302 }
6303 }
6304
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 // The limit can be very large (0xffffffffu), but since the pattern
6306 // isn't empty, we can never create more parts than ~half the length
6307 // of the subject.
6308
6309 if (!subject->IsFlat()) FlattenString(subject);
6310
6311 static const int kMaxInitialListCapacity = 16;
6312
danno@chromium.org40cb8782011-05-25 07:58:50 +00006313 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006314
6315 // Find (up to limit) indices of separator and end-of-string in subject
6316 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6317 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006318 if (!pattern->IsFlat()) FlattenString(pattern);
6319
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006320 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006321
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006322 if (static_cast<uint32_t>(indices.length()) < limit) {
6323 indices.Add(subject_length);
6324 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006325
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006326 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006327
6328 // Create JSArray of substrings separated by separator.
6329 int part_count = indices.length();
6330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006331 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006332 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006333 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006334 result->set_length(Smi::FromInt(part_count));
6335
6336 ASSERT(result->HasFastElements());
6337
6338 if (part_count == 1 && indices.at(0) == subject_length) {
6339 FixedArray::cast(result->elements())->set(0, *subject);
6340 return *result;
6341 }
6342
6343 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6344 int part_start = 0;
6345 for (int i = 0; i < part_count; i++) {
6346 HandleScope local_loop_handle;
6347 int part_end = indices.at(i);
6348 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006349 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006350 elements->set(i, *substring);
6351 part_start = part_end + pattern_length;
6352 }
6353
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006354 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006355 if (result->HasFastElements()) {
6356 StringSplitCache::Enter(isolate->heap(),
6357 isolate->heap()->string_split_cache(),
6358 *subject,
6359 *pattern,
6360 *elements);
6361 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006362 }
6363
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006364 return *result;
6365}
6366
6367
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006368// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369// one-char strings in the cache. Gives up on the first char that is
6370// not in the cache and fills the remainder with smi zeros. Returns
6371// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372static int CopyCachedAsciiCharsToArray(Heap* heap,
6373 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006374 FixedArray* elements,
6375 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006376 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006377 FixedArray* ascii_cache = heap->single_character_string_cache();
6378 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006379 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006380 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006381 for (i = 0; i < length; ++i) {
6382 Object* value = ascii_cache->get(chars[i]);
6383 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006384 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006385 }
6386 if (i < length) {
6387 ASSERT(Smi::FromInt(0) == 0);
6388 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6389 }
6390#ifdef DEBUG
6391 for (int j = 0; j < length; ++j) {
6392 Object* element = elements->get(j);
6393 ASSERT(element == Smi::FromInt(0) ||
6394 (element->IsString() && String::cast(element)->LooksValid()));
6395 }
6396#endif
6397 return i;
6398}
6399
6400
6401// Converts a String to JSArray.
6402// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006403RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006405 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006406 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006407 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006409 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006410 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006411
6412 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006413 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006414 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006415 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006416 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417 { MaybeObject* maybe_obj =
6418 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006419 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6420 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006421 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006422 String::FlatContent content = s->GetFlatContent();
6423 if (content.IsAscii()) {
6424 Vector<const char> chars = content.ToAsciiVector();
6425 // Note, this will initialize all elements (not only the prefix)
6426 // to prevent GC from seeing partially initialized array.
6427 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6428 chars.start(),
6429 *elements,
6430 length);
6431 } else {
6432 MemsetPointer(elements->data_start(),
6433 isolate->heap()->undefined_value(),
6434 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006435 }
6436 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006438 }
6439 for (int i = position; i < length; ++i) {
6440 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6441 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006442 }
6443
6444#ifdef DEBUG
6445 for (int i = 0; i < length; ++i) {
6446 ASSERT(String::cast(elements->get(i))->length() == 1);
6447 }
6448#endif
6449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006450 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006451}
6452
6453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006454RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006455 NoHandleAllocation ha;
6456 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006457 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006458 return value->ToObject();
6459}
6460
6461
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006462bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006463 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006464 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006465 return char_length == 0;
6466}
6467
6468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006469RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006470 NoHandleAllocation ha;
6471 ASSERT(args.length() == 1);
6472
6473 Object* number = args[0];
6474 RUNTIME_ASSERT(number->IsNumber());
6475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006476 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477}
6478
6479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006480RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006481 NoHandleAllocation ha;
6482 ASSERT(args.length() == 1);
6483
6484 Object* number = args[0];
6485 RUNTIME_ASSERT(number->IsNumber());
6486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006488}
6489
6490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006491RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 1);
6494
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006495 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006496
6497 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6498 if (number > 0 && number <= Smi::kMaxValue) {
6499 return Smi::FromInt(static_cast<int>(number));
6500 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502}
6503
6504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006505RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006506 NoHandleAllocation ha;
6507 ASSERT(args.length() == 1);
6508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006509 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006510
6511 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6512 if (number > 0 && number <= Smi::kMaxValue) {
6513 return Smi::FromInt(static_cast<int>(number));
6514 }
6515
6516 double double_value = DoubleToInteger(number);
6517 // Map both -0 and +0 to +0.
6518 if (double_value == 0) double_value = 0;
6519
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006521}
6522
6523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006524RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525 NoHandleAllocation ha;
6526 ASSERT(args.length() == 1);
6527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006528 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006530}
6531
6532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006533RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 NoHandleAllocation ha;
6535 ASSERT(args.length() == 1);
6536
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006537 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006538
6539 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6540 if (number > 0 && number <= Smi::kMaxValue) {
6541 return Smi::FromInt(static_cast<int>(number));
6542 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544}
6545
6546
ager@chromium.org870a0b62008-11-04 11:43:05 +00006547// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6548// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006549RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006550 NoHandleAllocation ha;
6551 ASSERT(args.length() == 1);
6552
6553 Object* obj = args[0];
6554 if (obj->IsSmi()) {
6555 return obj;
6556 }
6557 if (obj->IsHeapNumber()) {
6558 double value = HeapNumber::cast(obj)->value();
6559 int int_value = FastD2I(value);
6560 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6561 return Smi::FromInt(int_value);
6562 }
6563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006564 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006565}
6566
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006571 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006572}
6573
6574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006575RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 NoHandleAllocation ha;
6577 ASSERT(args.length() == 2);
6578
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006579 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6580 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582}
6583
6584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586 NoHandleAllocation ha;
6587 ASSERT(args.length() == 2);
6588
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006589 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6590 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006591 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592}
6593
6594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006595RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596 NoHandleAllocation ha;
6597 ASSERT(args.length() == 2);
6598
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006599 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6600 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602}
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 1);
6608
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006609 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006610 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611}
6612
6613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006614RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006615 NoHandleAllocation ha;
6616 ASSERT(args.length() == 0);
6617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006618 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006619}
6620
6621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006622RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623 NoHandleAllocation ha;
6624 ASSERT(args.length() == 2);
6625
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006626 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6627 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629}
6630
6631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006632RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 NoHandleAllocation ha;
6634 ASSERT(args.length() == 2);
6635
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006636 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6637 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638
ager@chromium.org3811b432009-10-28 14:53:37 +00006639 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006640 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006648 CONVERT_ARG_CHECKED(String, str1, 0);
6649 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006650 isolate->counters()->string_add_runtime()->Increment();
6651 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006655template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006656static inline void StringBuilderConcatHelper(String* special,
6657 sinkchar* sink,
6658 FixedArray* fixed_array,
6659 int array_length) {
6660 int position = 0;
6661 for (int i = 0; i < array_length; i++) {
6662 Object* element = fixed_array->get(i);
6663 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006664 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006665 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006666 int pos;
6667 int len;
6668 if (encoded_slice > 0) {
6669 // Position and length encoded in one smi.
6670 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6671 len = StringBuilderSubstringLength::decode(encoded_slice);
6672 } else {
6673 // Position and length encoded in two smis.
6674 Object* obj = fixed_array->get(++i);
6675 ASSERT(obj->IsSmi());
6676 pos = Smi::cast(obj)->value();
6677 len = -encoded_slice;
6678 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006679 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006680 sink + position,
6681 pos,
6682 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006683 position += len;
6684 } else {
6685 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006686 int element_length = string->length();
6687 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006688 position += element_length;
6689 }
6690 }
6691}
6692
6693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006694RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006696 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006697 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006698 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006699 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006700 return Failure::OutOfMemoryException();
6701 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006702 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006703 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006704
6705 // This assumption is used by the slice encoding in one or two smis.
6706 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6707
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006708 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006709 if (maybe_result->IsFailure()) return maybe_result;
6710
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006711 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 }
6715 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006716 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719
6720 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006721 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 } else if (array_length == 1) {
6723 Object* first = fixed_array->get(0);
6724 if (first->IsString()) return first;
6725 }
6726
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006727 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 int position = 0;
6729 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006730 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731 Object* elt = fixed_array->get(i);
6732 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006733 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006734 int smi_value = Smi::cast(elt)->value();
6735 int pos;
6736 int len;
6737 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006738 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006739 pos = StringBuilderSubstringPosition::decode(smi_value);
6740 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006741 } else {
6742 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006743 len = -smi_value;
6744 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006745 i++;
6746 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006747 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006748 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006749 Object* next_smi = fixed_array->get(i);
6750 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006752 }
6753 pos = Smi::cast(next_smi)->value();
6754 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006758 ASSERT(pos >= 0);
6759 ASSERT(len >= 0);
6760 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006762 }
6763 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 } else if (elt->IsString()) {
6765 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006766 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006767 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006768 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006771 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006772 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006775 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006776 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006777 return Failure::OutOfMemoryException();
6778 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006779 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 }
6781
6782 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006785 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 { MaybeObject* maybe_object =
6787 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006788 if (!maybe_object->ToObject(&object)) return maybe_object;
6789 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006790 SeqAsciiString* answer = SeqAsciiString::cast(object);
6791 StringBuilderConcatHelper(special,
6792 answer->GetChars(),
6793 fixed_array,
6794 array_length);
6795 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006797 { MaybeObject* maybe_object =
6798 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006799 if (!maybe_object->ToObject(&object)) return maybe_object;
6800 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006801 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6802 StringBuilderConcatHelper(special,
6803 answer->GetChars(),
6804 fixed_array,
6805 array_length);
6806 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808}
6809
6810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006811RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006812 NoHandleAllocation ha;
6813 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006814 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006815 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006817 return Failure::OutOfMemoryException();
6818 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006819 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006820 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006821
6822 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006823 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006824 }
6825 FixedArray* fixed_array = FixedArray::cast(array->elements());
6826 if (fixed_array->length() < array_length) {
6827 array_length = fixed_array->length();
6828 }
6829
6830 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006832 } else if (array_length == 1) {
6833 Object* first = fixed_array->get(0);
6834 if (first->IsString()) return first;
6835 }
6836
6837 int separator_length = separator->length();
6838 int max_nof_separators =
6839 (String::kMaxLength + separator_length - 1) / separator_length;
6840 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006841 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 return Failure::OutOfMemoryException();
6843 }
6844 int length = (array_length - 1) * separator_length;
6845 for (int i = 0; i < array_length; i++) {
6846 Object* element_obj = fixed_array->get(i);
6847 if (!element_obj->IsString()) {
6848 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006849 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006850 }
6851 String* element = String::cast(element_obj);
6852 int increment = element->length();
6853 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006854 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006855 return Failure::OutOfMemoryException();
6856 }
6857 length += increment;
6858 }
6859
6860 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006861 { MaybeObject* maybe_object =
6862 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006863 if (!maybe_object->ToObject(&object)) return maybe_object;
6864 }
6865 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6866
6867 uc16* sink = answer->GetChars();
6868#ifdef DEBUG
6869 uc16* end = sink + length;
6870#endif
6871
6872 String* first = String::cast(fixed_array->get(0));
6873 int first_length = first->length();
6874 String::WriteToFlat(first, sink, 0, first_length);
6875 sink += first_length;
6876
6877 for (int i = 1; i < array_length; i++) {
6878 ASSERT(sink + separator_length <= end);
6879 String::WriteToFlat(separator, sink, 0, separator_length);
6880 sink += separator_length;
6881
6882 String* element = String::cast(fixed_array->get(i));
6883 int element_length = element->length();
6884 ASSERT(sink + element_length <= end);
6885 String::WriteToFlat(element, sink, 0, element_length);
6886 sink += element_length;
6887 }
6888 ASSERT(sink == end);
6889
6890 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6891 return answer;
6892}
6893
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006894template <typename Char>
6895static void JoinSparseArrayWithSeparator(FixedArray* elements,
6896 int elements_length,
6897 uint32_t array_length,
6898 String* separator,
6899 Vector<Char> buffer) {
6900 int previous_separator_position = 0;
6901 int separator_length = separator->length();
6902 int cursor = 0;
6903 for (int i = 0; i < elements_length; i += 2) {
6904 int position = NumberToInt32(elements->get(i));
6905 String* string = String::cast(elements->get(i + 1));
6906 int string_length = string->length();
6907 if (string->length() > 0) {
6908 while (previous_separator_position < position) {
6909 String::WriteToFlat<Char>(separator, &buffer[cursor],
6910 0, separator_length);
6911 cursor += separator_length;
6912 previous_separator_position++;
6913 }
6914 String::WriteToFlat<Char>(string, &buffer[cursor],
6915 0, string_length);
6916 cursor += string->length();
6917 }
6918 }
6919 if (separator_length > 0) {
6920 // Array length must be representable as a signed 32-bit number,
6921 // otherwise the total string length would have been too large.
6922 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6923 int last_array_index = static_cast<int>(array_length - 1);
6924 while (previous_separator_position < last_array_index) {
6925 String::WriteToFlat<Char>(separator, &buffer[cursor],
6926 0, separator_length);
6927 cursor += separator_length;
6928 previous_separator_position++;
6929 }
6930 }
6931 ASSERT(cursor <= buffer.length());
6932}
6933
6934
6935RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6936 NoHandleAllocation ha;
6937 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006938 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006939 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6940 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006941 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006942 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006943 // elements_array is fast-mode JSarray of alternating positions
6944 // (increasing order) and strings.
6945 // array_length is length of original array (used to add separators);
6946 // separator is string to put between elements. Assumed to be non-empty.
6947
6948 // Find total length of join result.
6949 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006950 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006951 int max_string_length;
6952 if (is_ascii) {
6953 max_string_length = SeqAsciiString::kMaxLength;
6954 } else {
6955 max_string_length = SeqTwoByteString::kMaxLength;
6956 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006957 bool overflow = false;
6958 CONVERT_NUMBER_CHECKED(int, elements_length,
6959 Int32, elements_array->length());
6960 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6961 FixedArray* elements = FixedArray::cast(elements_array->elements());
6962 for (int i = 0; i < elements_length; i += 2) {
6963 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006964 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6965 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006966 int length = string->length();
6967 if (is_ascii && !string->IsAsciiRepresentation()) {
6968 is_ascii = false;
6969 max_string_length = SeqTwoByteString::kMaxLength;
6970 }
6971 if (length > max_string_length ||
6972 max_string_length - length < string_length) {
6973 overflow = true;
6974 break;
6975 }
6976 string_length += length;
6977 }
6978 int separator_length = separator->length();
6979 if (!overflow && separator_length > 0) {
6980 if (array_length <= 0x7fffffffu) {
6981 int separator_count = static_cast<int>(array_length) - 1;
6982 int remaining_length = max_string_length - string_length;
6983 if ((remaining_length / separator_length) >= separator_count) {
6984 string_length += separator_length * (array_length - 1);
6985 } else {
6986 // Not room for the separators within the maximal string length.
6987 overflow = true;
6988 }
6989 } else {
6990 // Nonempty separator and at least 2^31-1 separators necessary
6991 // means that the string is too large to create.
6992 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6993 overflow = true;
6994 }
6995 }
6996 if (overflow) {
6997 // Throw OutOfMemory exception for creating too large a string.
6998 V8::FatalProcessOutOfMemory("Array join result too large.");
6999 }
7000
7001 if (is_ascii) {
7002 MaybeObject* result_allocation =
7003 isolate->heap()->AllocateRawAsciiString(string_length);
7004 if (result_allocation->IsFailure()) return result_allocation;
7005 SeqAsciiString* result_string =
7006 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7007 JoinSparseArrayWithSeparator<char>(elements,
7008 elements_length,
7009 array_length,
7010 separator,
7011 Vector<char>(result_string->GetChars(),
7012 string_length));
7013 return result_string;
7014 } else {
7015 MaybeObject* result_allocation =
7016 isolate->heap()->AllocateRawTwoByteString(string_length);
7017 if (result_allocation->IsFailure()) return result_allocation;
7018 SeqTwoByteString* result_string =
7019 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7020 JoinSparseArrayWithSeparator<uc16>(elements,
7021 elements_length,
7022 array_length,
7023 separator,
7024 Vector<uc16>(result_string->GetChars(),
7025 string_length));
7026 return result_string;
7027 }
7028}
7029
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
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_NumberAnd) {
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_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052 NoHandleAllocation ha;
7053 ASSERT(args.length() == 2);
7054
7055 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7056 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007057 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058}
7059
7060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007061RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 NoHandleAllocation ha;
7063 ASSERT(args.length() == 1);
7064
7065 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067}
7068
7069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromInt32(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_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 return isolate->heap()->NumberFromUint32(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_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
7093
7094 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7095 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097}
7098
7099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007100RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 2);
7103
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007104 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7105 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7107 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7108 if (x == y) return Smi::FromInt(EQUAL);
7109 Object* result;
7110 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7111 result = Smi::FromInt(EQUAL);
7112 } else {
7113 result = Smi::FromInt(NOT_EQUAL);
7114 }
7115 return result;
7116}
7117
7118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007119RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120 NoHandleAllocation ha;
7121 ASSERT(args.length() == 2);
7122
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007123 CONVERT_ARG_CHECKED(String, x, 0);
7124 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007125
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007126 bool not_equal = !x->Equals(y);
7127 // This is slightly convoluted because the value that signifies
7128 // equality is 0 and inequality is 1 so we have to negate the result
7129 // from String::Equals.
7130 ASSERT(not_equal == 0 || not_equal == 1);
7131 STATIC_CHECK(EQUAL == 0);
7132 STATIC_CHECK(NOT_EQUAL == 1);
7133 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007134}
7135
7136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007137RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138 NoHandleAllocation ha;
7139 ASSERT(args.length() == 3);
7140
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007141 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7142 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 if (isnan(x) || isnan(y)) return args[2];
7144 if (x == y) return Smi::FromInt(EQUAL);
7145 if (isless(x, y)) return Smi::FromInt(LESS);
7146 return Smi::FromInt(GREATER);
7147}
7148
7149
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007150// Compare two Smis as if they were converted to strings and then
7151// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007152RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007153 NoHandleAllocation ha;
7154 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007155 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7156 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007157
7158 // If the integers are equal so are the string representations.
7159 if (x_value == y_value) return Smi::FromInt(EQUAL);
7160
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007161 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007162 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007163 if (x_value == 0 || y_value == 0)
7164 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007165
ager@chromium.org32912102009-01-16 10:38:43 +00007166 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007167 // smallest because the char code of '-' is less than the char code
7168 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007169
7170 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7171 // architectures using 32-bit Smis.
7172 uint32_t x_scaled = x_value;
7173 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007174 if (x_value < 0 || y_value < 0) {
7175 if (y_value >= 0) return Smi::FromInt(LESS);
7176 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007177 x_scaled = -x_value;
7178 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007179 }
7180
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007181 static const uint32_t kPowersOf10[] = {
7182 1, 10, 100, 1000, 10*1000, 100*1000,
7183 1000*1000, 10*1000*1000, 100*1000*1000,
7184 1000*1000*1000
7185 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007186
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007187 // If the integers have the same number of decimal digits they can be
7188 // compared directly as the numeric order is the same as the
7189 // lexicographic order. If one integer has fewer digits, it is scaled
7190 // by some power of 10 to have the same number of digits as the longer
7191 // integer. If the scaled integers are equal it means the shorter
7192 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007194 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7195 int x_log2 = IntegerLog2(x_scaled);
7196 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7197 x_log10 -= x_scaled < kPowersOf10[x_log10];
7198
7199 int y_log2 = IntegerLog2(y_scaled);
7200 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7201 y_log10 -= y_scaled < kPowersOf10[y_log10];
7202
7203 int tie = EQUAL;
7204
7205 if (x_log10 < y_log10) {
7206 // X has fewer digits. We would like to simply scale up X but that
7207 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7208 // be scaled up to 9_000_000_000. So we scale up by the next
7209 // smallest power and scale down Y to drop one digit. It is OK to
7210 // drop one digit from the longer integer since the final digit is
7211 // past the length of the shorter integer.
7212 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7213 y_scaled /= 10;
7214 tie = LESS;
7215 } else if (y_log10 < x_log10) {
7216 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7217 x_scaled /= 10;
7218 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007219 }
7220
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007221 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7222 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7223 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007224}
7225
7226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007227static Object* StringInputBufferCompare(RuntimeState* state,
7228 String* x,
7229 String* y) {
7230 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7231 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007232 bufx.Reset(x);
7233 bufy.Reset(y);
7234 while (bufx.has_more() && bufy.has_more()) {
7235 int d = bufx.GetNext() - bufy.GetNext();
7236 if (d < 0) return Smi::FromInt(LESS);
7237 else if (d > 0) return Smi::FromInt(GREATER);
7238 }
7239
7240 // x is (non-trivial) prefix of y:
7241 if (bufy.has_more()) return Smi::FromInt(LESS);
7242 // y is prefix of x:
7243 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7244}
7245
7246
7247static Object* FlatStringCompare(String* x, String* y) {
7248 ASSERT(x->IsFlat());
7249 ASSERT(y->IsFlat());
7250 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7251 int prefix_length = x->length();
7252 if (y->length() < prefix_length) {
7253 prefix_length = y->length();
7254 equal_prefix_result = Smi::FromInt(GREATER);
7255 } else if (y->length() > prefix_length) {
7256 equal_prefix_result = Smi::FromInt(LESS);
7257 }
7258 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007259 String::FlatContent x_content = x->GetFlatContent();
7260 String::FlatContent y_content = y->GetFlatContent();
7261 if (x_content.IsAscii()) {
7262 Vector<const char> x_chars = x_content.ToAsciiVector();
7263 if (y_content.IsAscii()) {
7264 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007265 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007266 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007267 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007268 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7269 }
7270 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007271 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7272 if (y_content.IsAscii()) {
7273 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007274 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7275 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007276 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007277 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7278 }
7279 }
7280 Object* result;
7281 if (r == 0) {
7282 result = equal_prefix_result;
7283 } else {
7284 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7285 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 ASSERT(result ==
7287 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007288 return result;
7289}
7290
7291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007292RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007293 NoHandleAllocation ha;
7294 ASSERT(args.length() == 2);
7295
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007296 CONVERT_ARG_CHECKED(String, x, 0);
7297 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007299 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301 // A few fast case tests before we flatten.
7302 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007303 if (y->length() == 0) {
7304 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007305 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007306 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307 return Smi::FromInt(LESS);
7308 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007309
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007310 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007311 if (d < 0) return Smi::FromInt(LESS);
7312 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313
lrn@chromium.org303ada72010-10-27 09:33:13 +00007314 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007316 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7317 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007319 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7320 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007322 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324}
7325
7326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007327RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
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_acos()->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::ACOS, 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_asin) {
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_asin()->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::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344}
7345
7346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007347RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 NoHandleAllocation ha;
7349 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007350 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354}
7355
7356
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007357static const double kPiDividedBy4 = 0.78539816339744830962;
7358
7359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007360RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361 NoHandleAllocation ha;
7362 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007365 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7366 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367 double result;
7368 if (isinf(x) && isinf(y)) {
7369 // Make sure that the result in case of two infinite arguments
7370 // is a multiple of Pi / 4. The sign of the result is determined
7371 // by the first argument (x) and the sign of the second argument
7372 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 int multiplier = (x < 0) ? -1 : 1;
7374 if (y < 0) multiplier *= 3;
7375 result = multiplier * kPiDividedBy4;
7376 } else {
7377 result = atan2(x, y);
7378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
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_ceil()->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->heap()->NumberFromDouble(ceiling(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_cos) {
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_cos()->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::COS, 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_exp) {
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_exp()->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->transcendental_cache()->Get(TranscendentalCache::EXP, 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_floor) {
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_floor()->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->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 NoHandleAllocation ha;
7425 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430}
7431
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007432// Slow version of Math.pow. We check for fast paths for special cases.
7433// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007434RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435 NoHandleAllocation ha;
7436 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007439 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007440
7441 // If the second argument is a smi, it is much faster to call the
7442 // custom powi() function than the generic pow().
7443 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007444 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007445 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007446 }
7447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007448 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007449 int y_int = static_cast<int>(y);
7450 double result;
7451 if (y == y_int) {
7452 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7453 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007454 result = (isinf(x)) ? V8_INFINITY
7455 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007456 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007457 result = (isinf(x)) ? 0
7458 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007459 } else {
7460 result = power_double_double(x, y);
7461 }
7462 if (isnan(result)) return isolate->heap()->nan_value();
7463 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007464}
7465
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007466// 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 +00007467// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007468RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007469 NoHandleAllocation ha;
7470 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007471 isolate->counters()->math_pow()->Increment();
7472
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007473 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7474 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007475 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007476 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007477 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007478 double result = power_double_double(x, y);
7479 if (isnan(result)) return isolate->heap()->nan_value();
7480 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007481 }
7482}
7483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007485RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007486 NoHandleAllocation ha;
7487 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007489
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007490 if (!args[0]->IsHeapNumber()) {
7491 // Must be smi. Return the argument unchanged for all the other types
7492 // to make fuzz-natives test happy.
7493 return args[0];
7494 }
7495
7496 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7497
7498 double value = number->value();
7499 int exponent = number->get_exponent();
7500 int sign = number->get_sign();
7501
danno@chromium.org160a7b02011-04-18 15:51:38 +00007502 if (exponent < -1) {
7503 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7504 if (sign) return isolate->heap()->minus_zero_value();
7505 return Smi::FromInt(0);
7506 }
7507
7508 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7509 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007510 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007511 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007512 return Smi::FromInt(static_cast<int>(value + 0.5));
7513 }
7514
7515 // If the magnitude is big enough, there's no place for fraction part. If we
7516 // try to add 0.5 to this number, 1.0 will be added instead.
7517 if (exponent >= 52) {
7518 return number;
7519 }
7520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007522
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007523 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525}
7526
7527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007528RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
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_sin()->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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, 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_sqrt) {
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_sqrt()->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);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007544 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545}
7546
7547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007548RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007549 NoHandleAllocation ha;
7550 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007551 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007553 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007554 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007555}
7556
7557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007558RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007560 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007562 CONVERT_SMI_ARG_CHECKED(year, 0);
7563 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007564
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007565 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566}
7567
7568
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007569RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7570 HandleScope scope(isolate);
7571 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007572
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007573 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7574 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7575 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007576
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007577 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007578
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007579 Object* value = NULL;
7580 bool is_value_nan = false;
7581 if (isnan(time)) {
7582 value = isolate->heap()->nan_value();
7583 is_value_nan = true;
7584 } else if (!is_utc &&
7585 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7586 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7587 value = isolate->heap()->nan_value();
7588 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007589 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007590 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7591 if (time < -DateCache::kMaxTimeInMs ||
7592 time > DateCache::kMaxTimeInMs) {
7593 value = isolate->heap()->nan_value();
7594 is_value_nan = true;
7595 } else {
7596 MaybeObject* maybe_result =
7597 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7598 if (!maybe_result->ToObject(&value)) return maybe_result;
7599 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007600 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007601 date->SetValue(value, is_value_nan);
7602 return *date;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007603}
7604
7605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007606RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007607 HandleScope scope(isolate);
7608 ASSERT(args.length() == 3);
7609
7610 Handle<JSFunction> callee = args.at<JSFunction>(0);
7611 Object** parameters = reinterpret_cast<Object**>(args[1]);
7612 const int argument_count = Smi::cast(args[2])->value();
7613
7614 Handle<JSObject> result =
7615 isolate->factory()->NewArgumentsObject(callee, argument_count);
7616 // Allocate the elements if needed.
7617 int parameter_count = callee->shared()->formal_parameter_count();
7618 if (argument_count > 0) {
7619 if (parameter_count > 0) {
7620 int mapped_count = Min(argument_count, parameter_count);
7621 Handle<FixedArray> parameter_map =
7622 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7623 parameter_map->set_map(
7624 isolate->heap()->non_strict_arguments_elements_map());
7625
7626 Handle<Map> old_map(result->map());
7627 Handle<Map> new_map =
7628 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007629 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007630
7631 result->set_map(*new_map);
7632 result->set_elements(*parameter_map);
7633
7634 // Store the context and the arguments array at the beginning of the
7635 // parameter map.
7636 Handle<Context> context(isolate->context());
7637 Handle<FixedArray> arguments =
7638 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7639 parameter_map->set(0, *context);
7640 parameter_map->set(1, *arguments);
7641
7642 // Loop over the actual parameters backwards.
7643 int index = argument_count - 1;
7644 while (index >= mapped_count) {
7645 // These go directly in the arguments array and have no
7646 // corresponding slot in the parameter map.
7647 arguments->set(index, *(parameters - index - 1));
7648 --index;
7649 }
7650
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007651 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007652 while (index >= 0) {
7653 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007654 Handle<String> name(scope_info->ParameterName(index));
7655 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007656 bool duplicate = false;
7657 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007658 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007659 duplicate = true;
7660 break;
7661 }
7662 }
7663
7664 if (duplicate) {
7665 // This goes directly in the arguments array with a hole in the
7666 // parameter map.
7667 arguments->set(index, *(parameters - index - 1));
7668 parameter_map->set_the_hole(index + 2);
7669 } else {
7670 // The context index goes in the parameter map with a hole in the
7671 // arguments array.
7672 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007673 for (int j = 0; j < context_local_count; ++j) {
7674 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007675 context_index = j;
7676 break;
7677 }
7678 }
7679 ASSERT(context_index >= 0);
7680 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007681 parameter_map->set(index + 2, Smi::FromInt(
7682 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007683 }
7684
7685 --index;
7686 }
7687 } else {
7688 // If there is no aliasing, the arguments object elements are not
7689 // special in any way.
7690 Handle<FixedArray> elements =
7691 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7692 result->set_elements(*elements);
7693 for (int i = 0; i < argument_count; ++i) {
7694 elements->set(i, *(parameters - i - 1));
7695 }
7696 }
7697 }
7698 return *result;
7699}
7700
7701
7702RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007703 NoHandleAllocation ha;
7704 ASSERT(args.length() == 3);
7705
7706 JSFunction* callee = JSFunction::cast(args[0]);
7707 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007708 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007709
lrn@chromium.org303ada72010-10-27 09:33:13 +00007710 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007711 { MaybeObject* maybe_result =
7712 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007713 if (!maybe_result->ToObject(&result)) return maybe_result;
7714 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007715 // Allocate the elements if needed.
7716 if (length > 0) {
7717 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007718 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007719 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007720 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7721 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007722
7723 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007724 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007725 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007726 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007727
7728 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007729 for (int i = 0; i < length; i++) {
7730 array->set(i, *--parameters, mode);
7731 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007732 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007733 }
7734 return result;
7735}
7736
7737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007738RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007740 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007741 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7742 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7743 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744
whesse@chromium.org7b260152011-06-20 15:33:18 +00007745 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007746 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007747 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007749 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7750 context,
7751 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007752 return *result;
7753}
7754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007755
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007756// Find the arguments of the JavaScript function invocation that called
7757// into C++ code. Collect these in a newly allocated array of handles (possibly
7758// prefixed by a number of empty handles).
7759static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7760 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007761 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007762 // Find frame containing arguments passed to the caller.
7763 JavaScriptFrameIterator it;
7764 JavaScriptFrame* frame = it.frame();
7765 List<JSFunction*> functions(2);
7766 frame->GetFunctions(&functions);
7767 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007768 int inlined_jsframe_index = functions.length() - 1;
7769 JSFunction* inlined_function = functions[inlined_jsframe_index];
7770 Vector<SlotRef> args_slots =
7771 SlotRef::ComputeSlotMappingForArguments(
7772 frame,
7773 inlined_jsframe_index,
7774 inlined_function->shared()->formal_parameter_count());
7775
7776 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007777
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007778 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007779 SmartArrayPointer<Handle<Object> > param_data(
7780 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007781 for (int i = 0; i < args_count; i++) {
7782 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007783 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007784 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007785
7786 args_slots.Dispose();
7787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007788 return param_data;
7789 } else {
7790 it.AdvanceToArgumentsFrame();
7791 frame = it.frame();
7792 int args_count = frame->ComputeParametersCount();
7793
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007794 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007795 SmartArrayPointer<Handle<Object> > param_data(
7796 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007797 for (int i = 0; i < args_count; i++) {
7798 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007799 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007800 }
7801 return param_data;
7802 }
7803}
7804
7805
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007806RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7807 HandleScope scope(isolate);
7808 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007809 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007810 RUNTIME_ASSERT(args[3]->IsNumber());
7811 Handle<Object> bindee = args.at<Object>(1);
7812
7813 // TODO(lrn): Create bound function in C++ code from premade shared info.
7814 bound_function->shared()->set_bound(true);
7815 // Get all arguments of calling function (Function.prototype.bind).
7816 int argc = 0;
7817 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7818 // Don't count the this-arg.
7819 if (argc > 0) {
7820 ASSERT(*arguments[0] == args[2]);
7821 argc--;
7822 } else {
7823 ASSERT(args[2]->IsUndefined());
7824 }
7825 // Initialize array of bindings (function, this, and any existing arguments
7826 // if the function was already bound).
7827 Handle<FixedArray> new_bindings;
7828 int i;
7829 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7830 Handle<FixedArray> old_bindings(
7831 JSFunction::cast(*bindee)->function_bindings());
7832 new_bindings =
7833 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7834 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7835 i = 0;
7836 for (int n = old_bindings->length(); i < n; i++) {
7837 new_bindings->set(i, old_bindings->get(i));
7838 }
7839 } else {
7840 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7841 new_bindings = isolate->factory()->NewFixedArray(array_size);
7842 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7843 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7844 i = 2;
7845 }
7846 // Copy arguments, skipping the first which is "this_arg".
7847 for (int j = 0; j < argc; j++, i++) {
7848 new_bindings->set(i, *arguments[j + 1]);
7849 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007850 new_bindings->set_map_no_write_barrier(
7851 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007852 bound_function->set_function_bindings(*new_bindings);
7853
7854 // Update length.
7855 Handle<String> length_symbol = isolate->factory()->length_symbol();
7856 Handle<Object> new_length(args.at<Object>(3));
7857 PropertyAttributes attr =
7858 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7859 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7860 return *bound_function;
7861}
7862
7863
7864RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7865 HandleScope handles(isolate);
7866 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007867 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007868 if (callable->IsJSFunction()) {
7869 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7870 if (function->shared()->bound()) {
7871 Handle<FixedArray> bindings(function->function_bindings());
7872 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7873 return *isolate->factory()->NewJSArrayWithElements(bindings);
7874 }
7875 }
7876 return isolate->heap()->undefined_value();
7877}
7878
7879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007880RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007881 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007882 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007883 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007884 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007885 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007887 // The argument is a bound function. Extract its bound arguments
7888 // and callable.
7889 Handle<FixedArray> bound_args =
7890 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7891 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7892 Handle<Object> bound_function(
7893 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7894 ASSERT(!bound_function->IsJSFunction() ||
7895 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007898 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007899 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007900 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007901 param_data[i] = Handle<Object>(bound_args->get(
7902 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007903 }
7904
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007905 if (!bound_function->IsJSFunction()) {
7906 bool exception_thrown;
7907 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7908 &exception_thrown);
7909 if (exception_thrown) return Failure::Exception();
7910 }
7911 ASSERT(bound_function->IsJSFunction());
7912
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007913 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007914 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007915 Execution::New(Handle<JSFunction>::cast(bound_function),
7916 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007917 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007918 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007919 }
7920 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007921 return *result;
7922}
7923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007925static void TrySettingInlineConstructStub(Isolate* isolate,
7926 Handle<JSFunction> function) {
7927 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007928 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007929 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007930 }
7931 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007932 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007933 Handle<Code> code = compiler.CompileConstructStub(function);
7934 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007935 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007936}
7937
7938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007939RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007940 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941 ASSERT(args.length() == 1);
7942
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007943 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007944
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007945 // If the constructor isn't a proper function we throw a type error.
7946 if (!constructor->IsJSFunction()) {
7947 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7948 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007949 isolate->factory()->NewTypeError("not_constructor", arguments);
7950 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007951 }
7952
7953 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007954
7955 // If function should not have prototype, construction is not allowed. In this
7956 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007957 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007958 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7959 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007960 isolate->factory()->NewTypeError("not_constructor", arguments);
7961 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007962 }
7963
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007964#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007966 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007967 if (debug->StepInActive()) {
7968 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007969 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007970#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007971
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007972 if (function->has_initial_map()) {
7973 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 // The 'Function' function ignores the receiver object when
7975 // called using 'new' and creates a new JSFunction object that
7976 // is returned. The receiver object is only used for error
7977 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007978 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007979 // allocate JSFunctions since it does not properly initialize
7980 // the shared part of the function. Since the receiver is
7981 // ignored anyway, we use the global object as the receiver
7982 // instead of a new JSFunction object. This way, errors are
7983 // reported the same way whether or not 'Function' is called
7984 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007985 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007986 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007987 }
7988
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007989 // The function should be compiled for the optimization hints to be
7990 // available. We cannot use EnsureCompiled because that forces a
7991 // compilation through the shared function info which makes it
7992 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007993 if (!function->is_compiled()) {
7994 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7995 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007996
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007997 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007998 if (!function->has_initial_map() &&
7999 shared->IsInobjectSlackTrackingInProgress()) {
8000 // The tracking is already in progress for another function. We can only
8001 // track one initial_map at a time, so we force the completion before the
8002 // function is called as a constructor for the first time.
8003 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008004 }
8005
8006 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8008 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008009 // Delay setting the stub if inobject slack tracking is in progress.
8010 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008011 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008012 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 isolate->counters()->constructed_objects()->Increment();
8015 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008016
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008017 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018}
8019
8020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008021RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008022 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008023 ASSERT(args.length() == 1);
8024
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008025 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008026 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008028
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008029 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008030}
8031
8032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008033RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 ASSERT(args.length() == 1);
8036
8037 Handle<JSFunction> function = args.at<JSFunction>(0);
8038#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008039 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008041 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008042 PrintF("]\n");
8043 }
8044#endif
8045
lrn@chromium.org34e60782011-09-15 07:25:40 +00008046 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008048 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049 return Failure::Exception();
8050 }
8051
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008052 // All done. Return the compiled code.
8053 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008054 return function->code();
8055}
8056
8057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008058RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008059 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008060 ASSERT(args.length() == 1);
8061 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008062
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008063 function->shared()->set_profiler_ticks(0);
8064
lrn@chromium.org34e60782011-09-15 07:25:40 +00008065 // If the function is not compiled ignore the lazy
8066 // recompilation. This can happen if the debugger is activated and
8067 // the function is returned to the not compiled state.
8068 if (!function->shared()->is_compiled()) {
8069 function->ReplaceCode(function->shared()->code());
8070 return function->code();
8071 }
8072
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008073 // If the function is not optimizable or debugger is active continue using the
8074 // code from the full compiler.
8075 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008076 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008077 if (FLAG_trace_opt) {
8078 PrintF("[failed to optimize ");
8079 function->PrintName();
8080 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8081 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008082 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008083 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008084 function->ReplaceCode(function->shared()->code());
8085 return function->code();
8086 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008087 if (JSFunction::CompileOptimized(function,
8088 AstNode::kNoNumber,
8089 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008090 return function->code();
8091 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008092 if (FLAG_trace_opt) {
8093 PrintF("[failed to optimize ");
8094 function->PrintName();
8095 PrintF(": optimized compilation failed]\n");
8096 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008097 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008098 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008099}
8100
8101
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008102class ActivationsFinder : public ThreadVisitor {
8103 public:
8104 explicit ActivationsFinder(JSFunction* function)
8105 : function_(function), has_activations_(false) {}
8106
8107 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8108 if (has_activations_) return;
8109
8110 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8111 JavaScriptFrame* frame = it.frame();
8112 if (frame->is_optimized() && frame->function() == function_) {
8113 has_activations_ = true;
8114 return;
8115 }
8116 }
8117 }
8118
8119 bool has_activations() { return has_activations_; }
8120
8121 private:
8122 JSFunction* function_;
8123 bool has_activations_;
8124};
8125
8126
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008127static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8128 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008129 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008130 Handle<Object> arguments;
8131 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008132 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008133 if (arguments.is_null()) {
8134 // FunctionGetArguments can't throw an exception, so cast away the
8135 // doubt with an assert.
8136 arguments = Handle<Object>(
8137 Accessors::FunctionGetArguments(*function,
8138 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008139 ASSERT(*arguments != isolate->heap()->null_value());
8140 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008141 }
8142 frame->SetExpression(i, *arguments);
8143 }
8144 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008145}
8146
8147
8148RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8149 HandleScope scope(isolate);
8150 ASSERT(args.length() == 1);
8151 RUNTIME_ASSERT(args[0]->IsSmi());
8152 Deoptimizer::BailoutType type =
8153 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8154 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8155 ASSERT(isolate->heap()->IsAllocationAllowed());
8156 int jsframes = deoptimizer->jsframe_count();
8157
8158 deoptimizer->MaterializeHeapNumbers();
8159 delete deoptimizer;
8160
8161 JavaScriptFrameIterator it(isolate);
8162 for (int i = 0; i < jsframes - 1; i++) {
8163 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8164 it.Advance();
8165 }
8166
8167 JavaScriptFrame* frame = it.frame();
8168 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8169 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8170 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008172 if (type == Deoptimizer::EAGER) {
8173 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008174 }
8175
8176 // Avoid doing too much work when running with --always-opt and keep
8177 // the optimized code around.
8178 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008179 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008180 }
8181
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008182 // Find other optimized activations of the function.
8183 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008184 while (!it.done()) {
8185 JavaScriptFrame* frame = it.frame();
8186 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008187 has_other_activations = true;
8188 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008189 }
8190 it.Advance();
8191 }
8192
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008193 if (!has_other_activations) {
8194 ActivationsFinder activations_finder(*function);
8195 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8196 has_other_activations = activations_finder.has_activations();
8197 }
8198
8199 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008200 if (FLAG_trace_deopt) {
8201 PrintF("[removing optimized code for: ");
8202 function->PrintName();
8203 PrintF("]\n");
8204 }
8205 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008206 } else {
8207 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008209 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008210}
8211
8212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008213RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008214 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008215 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008216 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008217}
8218
8219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008220RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008221 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008222 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008223 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008224 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008225
8226 Deoptimizer::DeoptimizeFunction(*function);
8227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008229}
8230
8231
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008232RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8233#if defined(USE_SIMULATOR)
8234 return isolate->heap()->true_value();
8235#else
8236 return isolate->heap()->false_value();
8237#endif
8238}
8239
8240
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008241RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8242 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008243 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008244 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008245
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008246 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8247 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008248
8249 Code* unoptimized = function->shared()->code();
8250 if (args.length() == 2 &&
8251 unoptimized->kind() == Code::FUNCTION) {
8252 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8253 CHECK(type->IsEqualTo(CStrVector("osr")));
8254 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8255 unoptimized->set_allow_osr_at_loop_nesting_level(
8256 Code::kMaxLoopNestingMarker);
8257 }
8258
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008259 return isolate->heap()->undefined_value();
8260}
8261
8262
lrn@chromium.org1c092762011-05-09 09:42:16 +00008263RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8264 HandleScope scope(isolate);
8265 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008266 // The least significant bit (after untagging) indicates whether the
8267 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008268 if (!V8::UseCrankshaft()) {
8269 return Smi::FromInt(4); // 4 == "never".
8270 }
8271 if (FLAG_always_opt) {
8272 return Smi::FromInt(3); // 3 == "always".
8273 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008274 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008275 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8276 : Smi::FromInt(2); // 2 == "no".
8277}
8278
8279
8280RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8281 HandleScope scope(isolate);
8282 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008283 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008284 return Smi::FromInt(function->shared()->opt_count());
8285}
8286
8287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008288RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008290 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008291 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008292
8293 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008294 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008295
8296 // We have hit a back edge in an unoptimized frame for a function that was
8297 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008299 // Keep track of whether we've succeeded in optimizing.
8300 bool succeeded = unoptimized->optimizable();
8301 if (succeeded) {
8302 // If we are trying to do OSR when there are already optimized
8303 // activations of the function, it means (a) the function is directly or
8304 // indirectly recursive and (b) an optimized invocation has been
8305 // deoptimized so that we are currently in an unoptimized activation.
8306 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008307 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008308 while (succeeded && !it.done()) {
8309 JavaScriptFrame* frame = it.frame();
8310 succeeded = !frame->is_optimized() || frame->function() != *function;
8311 it.Advance();
8312 }
8313 }
8314
8315 int ast_id = AstNode::kNoNumber;
8316 if (succeeded) {
8317 // The top JS function is this one, the PC is somewhere in the
8318 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008319 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008320 JavaScriptFrame* frame = it.frame();
8321 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008322 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008323 ASSERT(unoptimized->contains(frame->pc()));
8324
8325 // Use linear search of the unoptimized code's stack check table to find
8326 // the AST id matching the PC.
8327 Address start = unoptimized->instruction_start();
8328 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008329 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008330 uint32_t table_length = Memory::uint32_at(table_cursor);
8331 table_cursor += kIntSize;
8332 for (unsigned i = 0; i < table_length; ++i) {
8333 // Table entries are (AST id, pc offset) pairs.
8334 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8335 if (pc_offset == target_pc_offset) {
8336 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8337 break;
8338 }
8339 table_cursor += 2 * kIntSize;
8340 }
8341 ASSERT(ast_id != AstNode::kNoNumber);
8342 if (FLAG_trace_osr) {
8343 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8344 function->PrintName();
8345 PrintF("]\n");
8346 }
8347
8348 // Try to compile the optimized code. A true return value from
8349 // CompileOptimized means that compilation succeeded, not necessarily
8350 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008351 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008352 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008353 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8354 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008355 if (data->OsrPcOffset()->value() >= 0) {
8356 if (FLAG_trace_osr) {
8357 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008358 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008359 }
8360 ASSERT(data->OsrAstId()->value() == ast_id);
8361 } else {
8362 // We may never generate the desired OSR entry if we emit an
8363 // early deoptimize.
8364 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008365 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008366 } else {
8367 succeeded = false;
8368 }
8369 }
8370
8371 // Revert to the original stack checks in the original unoptimized code.
8372 if (FLAG_trace_osr) {
8373 PrintF("[restoring original stack checks in ");
8374 function->PrintName();
8375 PrintF("]\n");
8376 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008377 Handle<Code> check_code;
8378#ifdef V8_TARGET_ARCH_IA32
8379 if (FLAG_count_based_interrupts) {
8380 InterruptStub interrupt_stub;
8381 check_code = interrupt_stub.GetCode();
8382 } else // NOLINT
8383#endif
8384 { // NOLINT
8385 StackCheckStub check_stub;
8386 check_code = check_stub.GetCode();
8387 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008388 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008389 Deoptimizer::RevertStackCheckCode(*unoptimized,
8390 *check_code,
8391 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008392
8393 // Allow OSR only at nesting level zero again.
8394 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8395
8396 // If the optimization attempt succeeded, return the AST id tagged as a
8397 // smi. This tells the builtin that we need to translate the unoptimized
8398 // frame to an optimized one.
8399 if (succeeded) {
8400 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8401 return Smi::FromInt(ast_id);
8402 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008403 if (function->IsMarkedForLazyRecompilation()) {
8404 function->ReplaceCode(function->shared()->code());
8405 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008406 return Smi::FromInt(-1);
8407 }
8408}
8409
8410
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008411RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8412 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8413 return isolate->heap()->undefined_value();
8414}
8415
8416
danno@chromium.orgc612e022011-11-10 11:38:15 +00008417RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8418 HandleScope scope(isolate);
8419 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008420 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008421 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8422 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008423
8424 // If there are too many arguments, allocate argv via malloc.
8425 const int argv_small_size = 10;
8426 Handle<Object> argv_small_buffer[argv_small_size];
8427 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8428 Handle<Object>* argv = argv_small_buffer;
8429 if (argc > argv_small_size) {
8430 argv = new Handle<Object>[argc];
8431 if (argv == NULL) return isolate->StackOverflow();
8432 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8433 }
8434
8435 for (int i = 0; i < argc; ++i) {
8436 MaybeObject* maybe = args[1 + i];
8437 Object* object;
8438 if (!maybe->To<Object>(&object)) return maybe;
8439 argv[i] = Handle<Object>(object);
8440 }
8441
8442 bool threw;
8443 Handle<JSReceiver> hfun(fun);
8444 Handle<Object> hreceiver(receiver);
8445 Handle<Object> result =
8446 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8447
8448 if (threw) return Failure::Exception();
8449 return *result;
8450}
8451
8452
lrn@chromium.org34e60782011-09-15 07:25:40 +00008453RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8454 HandleScope scope(isolate);
8455 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008456 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008457 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008458 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008459 CONVERT_SMI_ARG_CHECKED(offset, 3);
8460 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008461 ASSERT(offset >= 0);
8462 ASSERT(argc >= 0);
8463
8464 // If there are too many arguments, allocate argv via malloc.
8465 const int argv_small_size = 10;
8466 Handle<Object> argv_small_buffer[argv_small_size];
8467 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8468 Handle<Object>* argv = argv_small_buffer;
8469 if (argc > argv_small_size) {
8470 argv = new Handle<Object>[argc];
8471 if (argv == NULL) return isolate->StackOverflow();
8472 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8473 }
8474
8475 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008476 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008477 }
8478
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008479 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008480 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008481 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008482
8483 if (threw) return Failure::Exception();
8484 return *result;
8485}
8486
8487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490 ASSERT(args.length() == 1);
8491 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8492 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8493}
8494
8495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008496RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008498 ASSERT(args.length() == 1);
8499 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8500 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8501}
8502
8503
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008504RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008505 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008506 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008507
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008508 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008509 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008510 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008511 { MaybeObject* maybe_result =
8512 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008513 if (!maybe_result->ToObject(&result)) return maybe_result;
8514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008516 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008517
kasper.lund7276f142008-07-30 08:49:36 +00008518 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008519}
8520
lrn@chromium.org303ada72010-10-27 09:33:13 +00008521
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008522RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8523 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008524 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008525 JSObject* extension_object;
8526 if (args[0]->IsJSObject()) {
8527 extension_object = JSObject::cast(args[0]);
8528 } else {
8529 // Convert the object to a proper JavaScript object.
8530 MaybeObject* maybe_js_object = args[0]->ToObject();
8531 if (!maybe_js_object->To(&extension_object)) {
8532 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8533 HandleScope scope(isolate);
8534 Handle<Object> handle = args.at<Object>(0);
8535 Handle<Object> result =
8536 isolate->factory()->NewTypeError("with_expression",
8537 HandleVector(&handle, 1));
8538 return isolate->Throw(*result);
8539 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008540 return maybe_js_object;
8541 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008542 }
8543 }
8544
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008545 JSFunction* function;
8546 if (args[1]->IsSmi()) {
8547 // A smi sentinel indicates a context nested inside global code rather
8548 // than some function. There is a canonical empty function that can be
8549 // gotten from the global context.
8550 function = isolate->context()->global_context()->closure();
8551 } else {
8552 function = JSFunction::cast(args[1]);
8553 }
8554
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008555 Context* context;
8556 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008557 isolate->heap()->AllocateWithContext(function,
8558 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008559 extension_object);
8560 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008561 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008562 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008563}
8564
8565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008566RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008567 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008568 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008569 String* name = String::cast(args[0]);
8570 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008571 JSFunction* function;
8572 if (args[2]->IsSmi()) {
8573 // A smi sentinel indicates a context nested inside global code rather
8574 // than some function. There is a canonical empty function that can be
8575 // gotten from the global context.
8576 function = isolate->context()->global_context()->closure();
8577 } else {
8578 function = JSFunction::cast(args[2]);
8579 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008580 Context* context;
8581 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008582 isolate->heap()->AllocateCatchContext(function,
8583 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008584 name,
8585 thrown_object);
8586 if (!maybe_context->To(&context)) return maybe_context;
8587 isolate->set_context(context);
8588 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008589}
8590
8591
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008592RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8593 NoHandleAllocation ha;
8594 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008595 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008596 JSFunction* function;
8597 if (args[1]->IsSmi()) {
8598 // A smi sentinel indicates a context nested inside global code rather
8599 // than some function. There is a canonical empty function that can be
8600 // gotten from the global context.
8601 function = isolate->context()->global_context()->closure();
8602 } else {
8603 function = JSFunction::cast(args[1]);
8604 }
8605 Context* context;
8606 MaybeObject* maybe_context =
8607 isolate->heap()->AllocateBlockContext(function,
8608 isolate->context(),
8609 scope_info);
8610 if (!maybe_context->To(&context)) return maybe_context;
8611 isolate->set_context(context);
8612 return context;
8613}
8614
8615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008616RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008617 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008618 ASSERT(args.length() == 2);
8619
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008620 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8621 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622
8623 int index;
8624 PropertyAttributes attributes;
8625 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008626 BindingFlags binding_flags;
8627 Handle<Object> holder = context->Lookup(name,
8628 flags,
8629 &index,
8630 &attributes,
8631 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008633 // If the slot was not found the result is true.
8634 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008635 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636 }
8637
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008638 // If the slot was found in a context, it should be DONT_DELETE.
8639 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008640 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008641 }
8642
8643 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008644 // the global object, or the subject of a with. Try to delete it
8645 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008646 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008647 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008648}
8649
8650
ager@chromium.orga1645e22009-09-09 19:27:10 +00008651// A mechanism to return a pair of Object pointers in registers (if possible).
8652// How this is achieved is calling convention-dependent.
8653// All currently supported x86 compiles uses calling conventions that are cdecl
8654// variants where a 64-bit value is returned in two 32-bit registers
8655// (edx:eax on ia32, r1:r0 on ARM).
8656// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8657// In Win64 calling convention, a struct of two pointers is returned in memory,
8658// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008659#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008660struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008661 MaybeObject* x;
8662 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008663};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008664
lrn@chromium.org303ada72010-10-27 09:33:13 +00008665static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008666 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008667 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8668 // In Win64 they are assigned to a hidden first argument.
8669 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008670}
8671#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008672typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008673static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008675 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008677#endif
8678
8679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680static inline MaybeObject* Unhole(Heap* heap,
8681 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008682 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8684 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008685 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686}
8687
8688
danno@chromium.org40cb8782011-05-25 07:58:50 +00008689static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8690 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008691 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008692 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008693 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008694 JSFunction* context_extension_function =
8695 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008696 // If the holder isn't a context extension object, we just return it
8697 // as the receiver. This allows arguments objects to be used as
8698 // receivers, but only if they are put in the context scope chain
8699 // explicitly via a with-statement.
8700 Object* constructor = holder->map()->constructor();
8701 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008702 // Fall back to using the global object as the implicit receiver if
8703 // the property turns out to be a local variable allocated in a
8704 // context extension object - introduced via eval. Implicit global
8705 // receivers are indicated with the hole value.
8706 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008707}
8708
8709
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008710static ObjectPair LoadContextSlotHelper(Arguments args,
8711 Isolate* isolate,
8712 bool throw_error) {
8713 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008714 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008715
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008716 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008717 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008720 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008721
8722 int index;
8723 PropertyAttributes attributes;
8724 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008725 BindingFlags binding_flags;
8726 Handle<Object> holder = context->Lookup(name,
8727 flags,
8728 &index,
8729 &attributes,
8730 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008731
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008732 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008733 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008734 ASSERT(holder->IsContext());
8735 // If the "property" we were looking for is a local variable, the
8736 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008737 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008738 // Use the hole as the receiver to signal that the receiver is implicit
8739 // and that the global receiver should be used (as distinguished from an
8740 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008741 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008742 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008743 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008744 switch (binding_flags) {
8745 case MUTABLE_CHECK_INITIALIZED:
8746 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8747 if (value->IsTheHole()) {
8748 Handle<Object> reference_error =
8749 isolate->factory()->NewReferenceError("not_defined",
8750 HandleVector(&name, 1));
8751 return MakePair(isolate->Throw(*reference_error), NULL);
8752 }
8753 // FALLTHROUGH
8754 case MUTABLE_IS_INITIALIZED:
8755 case IMMUTABLE_IS_INITIALIZED:
8756 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8757 ASSERT(!value->IsTheHole());
8758 return MakePair(value, *receiver);
8759 case IMMUTABLE_CHECK_INITIALIZED:
8760 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8761 case MISSING_BINDING:
8762 UNREACHABLE();
8763 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765 }
8766
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008767 // Otherwise, if the slot was found the holder is a context extension
8768 // object, subject of a with, or a global object. We read the named
8769 // property from it.
8770 if (!holder.is_null()) {
8771 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8772 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008773 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008774 Handle<Object> receiver_handle(object->IsGlobalObject()
8775 ? GlobalObject::cast(*object)->global_receiver()
8776 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008777
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008778 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008779 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008780 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008781 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 }
8783
8784 if (throw_error) {
8785 // The property doesn't exist - throw exception.
8786 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008787 isolate->factory()->NewReferenceError("not_defined",
8788 HandleVector(&name, 1));
8789 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008791 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008792 return MakePair(isolate->heap()->undefined_value(),
8793 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794 }
8795}
8796
8797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008798RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008799 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008800}
8801
8802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008803RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008805}
8806
8807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008808RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008810 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008811
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008813 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8814 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008815 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8816 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8817 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818
8819 int index;
8820 PropertyAttributes attributes;
8821 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008822 BindingFlags binding_flags;
8823 Handle<Object> holder = context->Lookup(name,
8824 flags,
8825 &index,
8826 &attributes,
8827 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828
8829 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008830 // The property was found in a context slot.
8831 Handle<Context> context = Handle<Context>::cast(holder);
8832 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8833 context->get(index)->IsTheHole()) {
8834 Handle<Object> error =
8835 isolate->factory()->NewReferenceError("not_defined",
8836 HandleVector(&name, 1));
8837 return isolate->Throw(*error);
8838 }
8839 // Ignore if read_only variable.
8840 if ((attributes & READ_ONLY) == 0) {
8841 // Context is a fixed array and set cannot fail.
8842 context->set(index, *value);
8843 } else if (strict_mode == kStrictMode) {
8844 // Setting read only property in strict mode.
8845 Handle<Object> error =
8846 isolate->factory()->NewTypeError("strict_cannot_assign",
8847 HandleVector(&name, 1));
8848 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008849 }
8850 return *value;
8851 }
8852
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008853 // Slow case: The property is not in a context slot. It is either in a
8854 // context extension object, a property of the subject of a with, or a
8855 // property of the global object.
8856 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008858 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008859 // The property exists on the holder.
8860 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008861 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008862 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008864
8865 if (strict_mode == kStrictMode) {
8866 // Throw in strict mode (assignment to undefined variable).
8867 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008868 isolate->factory()->NewReferenceError(
8869 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008870 return isolate->Throw(*error);
8871 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008872 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008874 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008875 }
8876
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008877 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008878 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008879 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008880 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008881 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008882 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008883 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008884 // Setting read only property in strict mode.
8885 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 isolate->factory()->NewTypeError(
8887 "strict_cannot_assign", HandleVector(&name, 1));
8888 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889 }
8890 return *value;
8891}
8892
8893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008894RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896 ASSERT(args.length() == 1);
8897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008898 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899}
8900
8901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008902RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008903 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904 ASSERT(args.length() == 1);
8905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008906 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907}
8908
8909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008910RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008911 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008913}
8914
8915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008916RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 ASSERT(args.length() == 1);
8919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008920 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008921 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922 isolate->factory()->NewReferenceError("not_defined",
8923 HandleVector(&name, 1));
8924 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925}
8926
8927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008928RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008929 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930
8931 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008932 if (isolate->stack_guard()->IsStackOverflow()) {
8933 NoHandleAllocation na;
8934 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008936
ulan@chromium.org812308e2012-02-29 15:58:45 +00008937 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938}
8939
8940
yangguo@chromium.org56454712012-02-16 15:33:53 +00008941RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8942 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008943 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008944}
8945
8946
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947static int StackSize() {
8948 int n = 0;
8949 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8950 return n;
8951}
8952
8953
8954static void PrintTransition(Object* result) {
8955 // indentation
8956 { const int nmax = 80;
8957 int n = StackSize();
8958 if (n <= nmax)
8959 PrintF("%4d:%*s", n, n, "");
8960 else
8961 PrintF("%4d:%*s", n, nmax, "...");
8962 }
8963
8964 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008965 JavaScriptFrame::PrintTop(stdout, true, false);
8966 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008967 } else {
8968 // function result
8969 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008970 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 PrintF("\n");
8972 }
8973}
8974
8975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008976RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008977 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978 NoHandleAllocation ha;
8979 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008980 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981}
8982
8983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008984RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985 NoHandleAllocation ha;
8986 PrintTransition(args[0]);
8987 return args[0]; // return TOS
8988}
8989
8990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008991RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008992 NoHandleAllocation ha;
8993 ASSERT(args.length() == 1);
8994
8995#ifdef DEBUG
8996 if (args[0]->IsString()) {
8997 // If we have a string, assume it's a code "marker"
8998 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008999 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009001 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9002 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009003 } else {
9004 PrintF("DebugPrint: ");
9005 }
9006 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009007 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009008 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009009 HeapObject::cast(args[0])->map()->Print();
9010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009012 // ShortPrint is available in release mode. Print is not.
9013 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014#endif
9015 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009016 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017
9018 return args[0]; // return TOS
9019}
9020
9021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009022RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009023 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009025 isolate->PrintStack();
9026 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009027}
9028
9029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009030RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009032 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009033
9034 // According to ECMA-262, section 15.9.1, page 117, the precision of
9035 // the number in a Date object representing a particular instant in
9036 // time is milliseconds. Therefore, we floor the result of getting
9037 // the OS time.
9038 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040}
9041
9042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009043RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009045 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009047 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009048 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009049
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009050 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009051
9052 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009053 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009054 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009055 RUNTIME_ASSERT(output->HasFastElements());
9056
9057 AssertNoAllocation no_allocation;
9058
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009059 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009060 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9061 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009062 String::FlatContent str_content = str->GetFlatContent();
9063 if (str_content.IsAscii()) {
9064 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009065 output_array,
9066 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009068 ASSERT(str_content.IsTwoByte());
9069 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009070 output_array,
9071 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009072 }
9073
9074 if (result) {
9075 return *output;
9076 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009077 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009078 }
9079}
9080
9081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009082RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083 NoHandleAllocation ha;
9084 ASSERT(args.length() == 1);
9085
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009086 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009087 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9088 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009089 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009090}
9091
9092
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009093RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094 NoHandleAllocation ha;
9095 ASSERT(args.length() == 1);
9096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009097 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009098 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9099
9100 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009101}
9102
9103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009104RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009105 ASSERT(args.length() == 1);
9106 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009108 return JSGlobalObject::cast(global)->global_receiver();
9109}
9110
9111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009112RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009114 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009115 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009116
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009117 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009118 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009119 Handle<Object> result;
9120 if (source->IsSeqAsciiString()) {
9121 result = JsonParser<true>::Parse(source);
9122 } else {
9123 result = JsonParser<false>::Parse(source);
9124 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009125 if (result.is_null()) {
9126 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009127 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009128 return Failure::Exception();
9129 }
9130 return *result;
9131}
9132
9133
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009134bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9135 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009136 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9137 // Check with callback if set.
9138 AllowCodeGenerationFromStringsCallback callback =
9139 isolate->allow_code_gen_callback();
9140 if (callback == NULL) {
9141 // No callback set and code generation disallowed.
9142 return false;
9143 } else {
9144 // Callback set. Let it decide if code generation is allowed.
9145 VMState state(isolate, EXTERNAL);
9146 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009147 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009148}
9149
9150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009151RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009153 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009154 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009155
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009156 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009158
9159 // Check if global context allows code generation from
9160 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009161 if (context->allow_code_gen_from_strings()->IsFalse() &&
9162 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009163 return isolate->Throw(*isolate->factory()->NewError(
9164 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9165 }
9166
9167 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009168 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009169 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009170 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9173 context,
9174 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 return *fun;
9176}
9177
9178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179static ObjectPair CompileGlobalEval(Isolate* isolate,
9180 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009181 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009182 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009183 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009184 Handle<Context> context = Handle<Context>(isolate->context());
9185 Handle<Context> global_context = Handle<Context>(context->global_context());
9186
9187 // Check if global context allows code generation from
9188 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009189 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9190 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009191 isolate->Throw(*isolate->factory()->NewError(
9192 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9193 return MakePair(Failure::Exception(), NULL);
9194 }
9195
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009196 // Deal with a normal eval call with a string argument. Compile it
9197 // and return the compiled function bound in the local context.
9198 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9199 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009201 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009202 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009203 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009204 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009205 Handle<JSFunction> compiled =
9206 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009207 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009208 return MakePair(*compiled, *receiver);
9209}
9210
9211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009212RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009213 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009216 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009217
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009218 // If "eval" didn't refer to the original GlobalEval, it's not a
9219 // direct call to eval.
9220 // (And even if it is, but the first argument isn't a string, just let
9221 // execution default to an indirect call to eval, which will also return
9222 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009224 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009225 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009226 }
9227
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009228 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009229 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 return CompileGlobalEval(isolate,
9231 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009232 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009233 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009234 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009235}
9236
9237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009238RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239 // This utility adjusts the property attributes for newly created Function
9240 // object ("new Function(...)") by changing the map.
9241 // All it does is changing the prototype property to enumerable
9242 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009245 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009247 Handle<Map> map = func->shared()->is_classic_mode()
9248 ? isolate->function_instance_map()
9249 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250
9251 ASSERT(func->map()->instance_type() == map->instance_type());
9252 ASSERT(func->map()->instance_size() == map->instance_size());
9253 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009254 return *func;
9255}
9256
9257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009258RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009259 // Allocate a block of memory in NewSpace (filled with a filler).
9260 // Use as fallback for allocation in generated code when NewSpace
9261 // is full.
9262 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009263 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009264 int size = size_smi->value();
9265 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9266 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009267 Heap* heap = isolate->heap();
9268 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009269 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009270 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009271 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009272 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009273 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009274 }
9275 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009276 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009277}
9278
9279
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009280// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009281// array. Returns true if the element was pushed on the stack and
9282// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009283RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009284 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009285 CONVERT_ARG_CHECKED(JSArray, array, 0);
9286 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009287 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009288 int length = Smi::cast(array->length())->value();
9289 FixedArray* elements = FixedArray::cast(array->elements());
9290 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009292 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009293 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009294 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009295 { MaybeObject* maybe_obj =
9296 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009297 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9298 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009299 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009300}
9301
9302
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009303/**
9304 * A simple visitor visits every element of Array's.
9305 * The backend storage can be a fixed array for fast elements case,
9306 * or a dictionary for sparse array. Since Dictionary is a subtype
9307 * of FixedArray, the class can be used by both fast and slow cases.
9308 * The second parameter of the constructor, fast_elements, specifies
9309 * whether the storage is a FixedArray or Dictionary.
9310 *
9311 * An index limit is used to deal with the situation that a result array
9312 * length overflows 32-bit non-negative integer.
9313 */
9314class ArrayConcatVisitor {
9315 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 ArrayConcatVisitor(Isolate* isolate,
9317 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009318 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009319 isolate_(isolate),
9320 storage_(Handle<FixedArray>::cast(
9321 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009322 index_offset_(0u),
9323 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009324
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009325 ~ArrayConcatVisitor() {
9326 clear_storage();
9327 }
9328
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009329 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009330 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009331 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009332
9333 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009334 if (index < static_cast<uint32_t>(storage_->length())) {
9335 storage_->set(index, *elm);
9336 return;
9337 }
9338 // Our initial estimate of length was foiled, possibly by
9339 // getters on the arrays increasing the length of later arrays
9340 // during iteration.
9341 // This shouldn't happen in anything but pathological cases.
9342 SetDictionaryMode(index);
9343 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009344 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009345 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009346 Handle<SeededNumberDictionary> dict(
9347 SeededNumberDictionary::cast(*storage_));
9348 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009351 // Dictionary needed to grow.
9352 clear_storage();
9353 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009354 }
9355}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009356
9357 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009358 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9359 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009360 } else {
9361 index_offset_ += delta;
9362 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009363 }
9364
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009367 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009368 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009369 Handle<Map> map;
9370 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009371 map = isolate_->factory()->GetElementsTransitionMap(array,
9372 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009373 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009374 map = isolate_->factory()->GetElementsTransitionMap(array,
9375 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009376 }
9377 array->set_map(*map);
9378 array->set_length(*length);
9379 array->set_elements(*storage_);
9380 return array;
9381 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009382
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009383 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009384 // Convert storage to dictionary mode.
9385 void SetDictionaryMode(uint32_t index) {
9386 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009387 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009388 Handle<SeededNumberDictionary> slow_storage(
9389 isolate_->factory()->NewSeededNumberDictionary(
9390 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009391 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9392 for (uint32_t i = 0; i < current_length; i++) {
9393 HandleScope loop_scope;
9394 Handle<Object> element(current_storage->get(i));
9395 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009396 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009397 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009398 if (!new_storage.is_identical_to(slow_storage)) {
9399 slow_storage = loop_scope.CloseAndEscape(new_storage);
9400 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 }
9402 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009403 clear_storage();
9404 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009405 fast_elements_ = false;
9406 }
9407
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009408 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 isolate_->global_handles()->Destroy(
9410 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009411 }
9412
9413 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 storage_ = Handle<FixedArray>::cast(
9415 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009416 }
9417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009419 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009420 // Index after last seen index. Always less than or equal to
9421 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009422 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009423 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009424};
9425
9426
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009427static uint32_t EstimateElementCount(Handle<JSArray> array) {
9428 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9429 int element_count = 0;
9430 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009431 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009432 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009433 // Fast elements can't have lengths that are not representable by
9434 // a 32-bit signed integer.
9435 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9436 int fast_length = static_cast<int>(length);
9437 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9438 for (int i = 0; i < fast_length; i++) {
9439 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009440 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009441 break;
9442 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009443 case FAST_DOUBLE_ELEMENTS:
9444 // TODO(1810): Decide if it's worthwhile to implement this.
9445 UNREACHABLE();
9446 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009447 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009448 Handle<SeededNumberDictionary> dictionary(
9449 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009450 int capacity = dictionary->Capacity();
9451 for (int i = 0; i < capacity; i++) {
9452 Handle<Object> key(dictionary->KeyAt(i));
9453 if (dictionary->IsKey(*key)) {
9454 element_count++;
9455 }
9456 }
9457 break;
9458 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009459 case NON_STRICT_ARGUMENTS_ELEMENTS:
9460 case EXTERNAL_BYTE_ELEMENTS:
9461 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9462 case EXTERNAL_SHORT_ELEMENTS:
9463 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9464 case EXTERNAL_INT_ELEMENTS:
9465 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9466 case EXTERNAL_FLOAT_ELEMENTS:
9467 case EXTERNAL_DOUBLE_ELEMENTS:
9468 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009469 // External arrays are always dense.
9470 return length;
9471 }
9472 // As an estimate, we assume that the prototype doesn't contain any
9473 // inherited elements.
9474 return element_count;
9475}
9476
9477
9478
9479template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480static void IterateExternalArrayElements(Isolate* isolate,
9481 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009482 bool elements_are_ints,
9483 bool elements_are_guaranteed_smis,
9484 ArrayConcatVisitor* visitor) {
9485 Handle<ExternalArrayClass> array(
9486 ExternalArrayClass::cast(receiver->elements()));
9487 uint32_t len = static_cast<uint32_t>(array->length());
9488
9489 ASSERT(visitor != NULL);
9490 if (elements_are_ints) {
9491 if (elements_are_guaranteed_smis) {
9492 for (uint32_t j = 0; j < len; j++) {
9493 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009494 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009495 visitor->visit(j, e);
9496 }
9497 } else {
9498 for (uint32_t j = 0; j < len; j++) {
9499 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009500 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009501 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9502 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9503 visitor->visit(j, e);
9504 } else {
9505 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009506 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009507 visitor->visit(j, e);
9508 }
9509 }
9510 }
9511 } else {
9512 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009514 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009515 visitor->visit(j, e);
9516 }
9517 }
9518}
9519
9520
9521// Used for sorting indices in a List<uint32_t>.
9522static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9523 uint32_t a = *ap;
9524 uint32_t b = *bp;
9525 return (a == b) ? 0 : (a < b) ? -1 : 1;
9526}
9527
9528
9529static void CollectElementIndices(Handle<JSObject> object,
9530 uint32_t range,
9531 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009532 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009533 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009534 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009535 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009536 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9537 uint32_t length = static_cast<uint32_t>(elements->length());
9538 if (range < length) length = range;
9539 for (uint32_t i = 0; i < length; i++) {
9540 if (!elements->get(i)->IsTheHole()) {
9541 indices->Add(i);
9542 }
9543 }
9544 break;
9545 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009546 case FAST_DOUBLE_ELEMENTS: {
9547 // TODO(1810): Decide if it's worthwhile to implement this.
9548 UNREACHABLE();
9549 break;
9550 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009551 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009552 Handle<SeededNumberDictionary> dict(
9553 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009554 uint32_t capacity = dict->Capacity();
9555 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009556 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009557 Handle<Object> k(dict->KeyAt(j));
9558 if (dict->IsKey(*k)) {
9559 ASSERT(k->IsNumber());
9560 uint32_t index = static_cast<uint32_t>(k->Number());
9561 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009562 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009563 }
9564 }
9565 }
9566 break;
9567 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009568 default: {
9569 int dense_elements_length;
9570 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009571 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009572 dense_elements_length =
9573 ExternalPixelArray::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_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009577 dense_elements_length =
9578 ExternalByteArray::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_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009582 dense_elements_length =
9583 ExternalUnsignedByteArray::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_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009587 dense_elements_length =
9588 ExternalShortArray::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_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009592 dense_elements_length =
9593 ExternalUnsignedShortArray::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_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009597 dense_elements_length =
9598 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009599 break;
9600 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009601 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009602 dense_elements_length =
9603 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009604 break;
9605 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009606 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009607 dense_elements_length =
9608 ExternalFloatArray::cast(object->elements())->length();
9609 break;
9610 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009611 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009612 dense_elements_length =
9613 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009614 break;
9615 }
9616 default:
9617 UNREACHABLE();
9618 dense_elements_length = 0;
9619 break;
9620 }
9621 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9622 if (range <= length) {
9623 length = range;
9624 // We will add all indices, so we might as well clear it first
9625 // and avoid duplicates.
9626 indices->Clear();
9627 }
9628 for (uint32_t i = 0; i < length; i++) {
9629 indices->Add(i);
9630 }
9631 if (length == range) return; // All indices accounted for already.
9632 break;
9633 }
9634 }
9635
9636 Handle<Object> prototype(object->GetPrototype());
9637 if (prototype->IsJSObject()) {
9638 // The prototype will usually have no inherited element indices,
9639 // but we have to check.
9640 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9641 }
9642}
9643
9644
9645/**
9646 * A helper function that visits elements of a JSArray in numerical
9647 * order.
9648 *
9649 * The visitor argument called for each existing element in the array
9650 * with the element index and the element's value.
9651 * Afterwards it increments the base-index of the visitor by the array
9652 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009653 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009654 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009655static bool IterateElements(Isolate* isolate,
9656 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 ArrayConcatVisitor* visitor) {
9658 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9659 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009660 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009661 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 // Run through the elements FixedArray and use HasElement and GetElement
9663 // to check the prototype for missing elements.
9664 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9665 int fast_length = static_cast<int>(length);
9666 ASSERT(fast_length <= elements->length());
9667 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009668 HandleScope loop_scope(isolate);
9669 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009670 if (!element_value->IsTheHole()) {
9671 visitor->visit(j, element_value);
9672 } else if (receiver->HasElement(j)) {
9673 // Call GetElement on receiver, not its prototype, or getters won't
9674 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009675 element_value = Object::GetElement(receiver, j);
9676 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 visitor->visit(j, element_value);
9678 }
9679 }
9680 break;
9681 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009682 case FAST_DOUBLE_ELEMENTS: {
9683 // TODO(1810): Decide if it's worthwhile to implement this.
9684 UNREACHABLE();
9685 break;
9686 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009687 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009688 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009689 List<uint32_t> indices(dict->Capacity() / 2);
9690 // Collect all indices in the object and the prototypes less
9691 // than length. This might introduce duplicates in the indices list.
9692 CollectElementIndices(receiver, length, &indices);
9693 indices.Sort(&compareUInt32);
9694 int j = 0;
9695 int n = indices.length();
9696 while (j < n) {
9697 HandleScope loop_scope;
9698 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009699 Handle<Object> element = Object::GetElement(receiver, index);
9700 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009701 visitor->visit(index, element);
9702 // Skip to next different index (i.e., omit duplicates).
9703 do {
9704 j++;
9705 } while (j < n && indices[j] == index);
9706 }
9707 break;
9708 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009709 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009710 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9711 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009713 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 visitor->visit(j, e);
9715 }
9716 break;
9717 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009718 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009719 IterateExternalArrayElements<ExternalByteArray, int8_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_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009724 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_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_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009730 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 break;
9732 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009733 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009734 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009736 break;
9737 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009738 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009739 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009740 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 break;
9742 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009743 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009745 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 break;
9747 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009748 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009749 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009750 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009751 break;
9752 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009753 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009754 IterateExternalArrayElements<ExternalDoubleArray, double>(
9755 isolate, receiver, false, false, visitor);
9756 break;
9757 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009758 default:
9759 UNREACHABLE();
9760 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009761 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009763 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009764}
9765
9766
9767/**
9768 * Array::concat implementation.
9769 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009770 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009771 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009772 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009773RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009774 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009775 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009776
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009777 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009778 int argument_count = static_cast<int>(arguments->length()->Number());
9779 RUNTIME_ASSERT(arguments->HasFastElements());
9780 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009781
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009782 // Pass 1: estimate the length and number of elements of the result.
9783 // The actual length can be larger if any of the arguments have getters
9784 // that mutate other arguments (but will otherwise be precise).
9785 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009786
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009787 uint32_t estimate_result_length = 0;
9788 uint32_t estimate_nof_elements = 0;
9789 {
9790 for (int i = 0; i < argument_count; i++) {
9791 HandleScope loop_scope;
9792 Handle<Object> obj(elements->get(i));
9793 uint32_t length_estimate;
9794 uint32_t element_estimate;
9795 if (obj->IsJSArray()) {
9796 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009797 // TODO(1810): Find out if it's worthwhile to properly support
9798 // arbitrary ElementsKinds. For now, pessimistically transition to
9799 // FAST_ELEMENTS.
9800 if (array->HasFastDoubleElements()) {
9801 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009802 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009803 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009804 length_estimate =
9805 static_cast<uint32_t>(array->length()->Number());
9806 element_estimate =
9807 EstimateElementCount(array);
9808 } else {
9809 length_estimate = 1;
9810 element_estimate = 1;
9811 }
9812 // Avoid overflows by capping at kMaxElementCount.
9813 if (JSObject::kMaxElementCount - estimate_result_length <
9814 length_estimate) {
9815 estimate_result_length = JSObject::kMaxElementCount;
9816 } else {
9817 estimate_result_length += length_estimate;
9818 }
9819 if (JSObject::kMaxElementCount - estimate_nof_elements <
9820 element_estimate) {
9821 estimate_nof_elements = JSObject::kMaxElementCount;
9822 } else {
9823 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009824 }
9825 }
9826 }
9827
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009828 // If estimated number of elements is more than half of length, a
9829 // fixed array (fast case) is more time and space-efficient than a
9830 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009831 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009832
9833 Handle<FixedArray> storage;
9834 if (fast_case) {
9835 // The backing storage array must have non-existing elements to
9836 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009837 storage = isolate->factory()->NewFixedArrayWithHoles(
9838 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009839 } else {
9840 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9841 uint32_t at_least_space_for = estimate_nof_elements +
9842 (estimate_nof_elements >> 2);
9843 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009844 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009845 }
9846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009847 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009848
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 for (int i = 0; i < argument_count; i++) {
9850 Handle<Object> obj(elements->get(i));
9851 if (obj->IsJSArray()) {
9852 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009853 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009854 return Failure::Exception();
9855 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009856 } else {
9857 visitor.visit(0, obj);
9858 visitor.increase_index_offset(1);
9859 }
9860 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009861
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009862 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009863}
9864
9865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866// This will not allocate (flatten the string), but it may run
9867// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009868RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869 NoHandleAllocation ha;
9870 ASSERT(args.length() == 1);
9871
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009872 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009873 StringInputBuffer buffer(string);
9874 while (buffer.has_more()) {
9875 uint16_t character = buffer.GetNext();
9876 PrintF("%c", character);
9877 }
9878 return string;
9879}
9880
ager@chromium.org5ec48922009-05-05 07:25:34 +00009881// Moves all own elements of an object, that are below a limit, to positions
9882// starting at zero. All undefined values are placed after non-undefined values,
9883// and are followed by non-existing element. Does not change the length
9884// property.
9885// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009886RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009887 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009888 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009889 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9890 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009891}
9892
9893
9894// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009895RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009897 CONVERT_ARG_CHECKED(JSArray, from, 0);
9898 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009899 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009900 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009901 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009902 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9903 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009904 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009905 } else if (new_elements->map() ==
9906 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009907 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009908 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009909 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009910 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009911 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009912 Object* new_map;
9913 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009914 to->set_map(Map::cast(new_map));
9915 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009917 Object* obj;
9918 { MaybeObject* maybe_obj = from->ResetElements();
9919 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9920 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009921 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922 return to;
9923}
9924
9925
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009926// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009927RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009928 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009929 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009930 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009932 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9933 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009934 } else if (object->IsJSArray()) {
9935 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009936 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009937 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009938 }
9939}
9940
9941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009942RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009944
9945 ASSERT_EQ(3, args.length());
9946
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009947 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009948 Handle<Object> key1 = args.at<Object>(1);
9949 Handle<Object> key2 = args.at<Object>(2);
9950
9951 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009952 if (!key1->ToArrayIndex(&index1)
9953 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009954 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009955 }
9956
ager@chromium.orgac091b72010-05-05 07:34:42 +00009957 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009958 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009960 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009961 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009962
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009963 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009964 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009965 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009966 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009969}
9970
9971
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009972// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009973// might have elements. Can either return keys (positive integers) or
9974// intervals (pair of a negative integer (-start-1) followed by a
9975// positive (length)) or undefined values.
9976// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009977RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009979 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009980 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009982 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009983 // Create an array and get all the keys into it, then remove all the
9984 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009985 bool threw = false;
9986 Handle<FixedArray> keys =
9987 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9988 if (threw) return Failure::Exception();
9989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990 int keys_length = keys->length();
9991 for (int i = 0; i < keys_length; i++) {
9992 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009993 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009994 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 // Zap invalid keys.
9996 keys->set_undefined(i);
9997 }
9998 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010001 ASSERT(array->HasFastElements() ||
10002 array->HasFastSmiOnlyElements() ||
10003 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010006 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010007 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010008 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010009 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010010 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010011 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010012 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010014 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015 }
10016}
10017
10018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010019RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010021 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10022 CONVERT_ARG_CHECKED(String, name, 1);
10023 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010024 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10025 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010026}
10027
10028
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010029#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010030RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010031 ASSERT(args.length() == 0);
10032 return Execution::DebugBreakHelper();
10033}
10034
10035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010036// Helper functions for wrapping and unwrapping stack frame ids.
10037static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010038 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010039 return Smi::FromInt(id >> 2);
10040}
10041
10042
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010043static StackFrame::Id UnwrapFrameId(int wrapped) {
10044 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045}
10046
10047
10048// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010049// args[0]: debug event listener function to set or null or undefined for
10050// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010051// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010052RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010054 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10055 args[0]->IsUndefined() ||
10056 args[0]->IsNull());
10057 Handle<Object> callback = args.at<Object>(0);
10058 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010060
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010061 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010062}
10063
10064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010065RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010066 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 isolate->stack_guard()->DebugBreak();
10068 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010069}
10070
10071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072static MaybeObject* DebugLookupResultValue(Heap* heap,
10073 Object* receiver,
10074 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010075 LookupResult* result,
10076 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010077 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010078 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010079 case NORMAL:
10080 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010081 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010083 }
10084 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010085 case FIELD:
10086 value =
10087 JSObject::cast(
10088 result->holder())->FastPropertyAt(result->GetFieldIndex());
10089 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010091 }
10092 return value;
10093 case CONSTANT_FUNCTION:
10094 return result->GetConstantFunction();
10095 case CALLBACKS: {
10096 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010097 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010098 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10099 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010100 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010101 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010102 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103 maybe_value = heap->isolate()->pending_exception();
10104 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010105 if (caught_exception != NULL) {
10106 *caught_exception = true;
10107 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010108 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010109 }
10110 return value;
10111 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010112 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010113 }
10114 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010116 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010117 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010118 case CONSTANT_TRANSITION:
10119 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010120 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010121 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010123 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010125 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010126 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127}
10128
10129
ager@chromium.org32912102009-01-16 10:38:43 +000010130// Get debugger related details for an object property.
10131// args[0]: object holding property
10132// args[1]: name of the property
10133//
10134// The array returned contains the following information:
10135// 0: Property value
10136// 1: Property details
10137// 2: Property value is exception
10138// 3: Getter function if defined
10139// 4: Setter function if defined
10140// Items 2-4 are only filled if the property has either a getter or a setter
10141// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010142RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144
10145 ASSERT(args.length() == 2);
10146
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010147 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10148 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010149
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010150 // Make sure to set the current context to the context before the debugger was
10151 // entered (if the debugger is entered). The reason for switching context here
10152 // is that for some property lookups (accessors and interceptors) callbacks
10153 // into the embedding application can occour, and the embedding application
10154 // could have the assumption that its own global context is the current
10155 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010156 SaveContext save(isolate);
10157 if (isolate->debug()->InDebugger()) {
10158 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010159 }
10160
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010161 // Skip the global proxy as it has no properties and always delegates to the
10162 // real global object.
10163 if (obj->IsJSGlobalProxy()) {
10164 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10165 }
10166
10167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 // Check if the name is trivially convertible to an index and get the element
10169 // if so.
10170 uint32_t index;
10171 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010172 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010173 Object* element_or_char;
10174 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010175 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010176 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10177 return maybe_element_or_char;
10178 }
10179 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010180 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010182 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010183 }
10184
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010185 // Find the number of objects making up this.
10186 int length = LocalPrototypeChainLength(*obj);
10187
10188 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010189 Handle<JSObject> jsproto = obj;
10190 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010191 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010192 jsproto->LocalLookup(*name, &result);
10193 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010194 // LookupResult is not GC safe as it holds raw object pointers.
10195 // GC can happen later in this code so put the required fields into
10196 // local variables using handles when required for later use.
10197 PropertyType result_type = result.type();
10198 Handle<Object> result_callback_obj;
10199 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010200 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10201 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010202 }
10203 Smi* property_details = result.GetPropertyDetails().AsSmi();
10204 // DebugLookupResultValue can cause GC so details from LookupResult needs
10205 // to be copied to handles before this.
10206 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010207 Object* raw_value;
10208 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 DebugLookupResultValue(isolate->heap(), *obj, *name,
10210 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010211 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10212 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010214
10215 // If the callback object is a fixed array then it contains JavaScript
10216 // getter and/or setter.
10217 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010218 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010219 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010221 details->set(0, *value);
10222 details->set(1, property_details);
10223 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010224 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010225 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010226 details->set(3, accessors->SafeGet(ACCESSOR_GETTER));
10227 details->set(4, accessors->SafeGet(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010228 }
10229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010231 }
10232 if (i < length - 1) {
10233 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10234 }
10235 }
10236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010237 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238}
10239
10240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010241RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010242 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243
10244 ASSERT(args.length() == 2);
10245
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010246 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10247 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010249 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 obj->Lookup(*name, &result);
10251 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010252 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255}
10256
10257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258// Return the property type calculated from the property details.
10259// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010260RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010262 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10263 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264}
10265
10266
10267// Return the property attribute calculated from the property details.
10268// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010269RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010271 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10272 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273}
10274
10275
10276// Return the property insertion index calculated from the property details.
10277// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010278RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010280 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10281 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282}
10283
10284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285// Return property value from named interceptor.
10286// args[0]: object
10287// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010288RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010289 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010291 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010293 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294
10295 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010296 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297}
10298
10299
10300// Return element value from indexed interceptor.
10301// args[0]: object
10302// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010303RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010306 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10308 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10309
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010310 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311}
10312
10313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010314RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 ASSERT(args.length() >= 1);
10316 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010317 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318 if (isolate->debug()->break_id() == 0 ||
10319 break_id != isolate->debug()->break_id()) {
10320 return isolate->Throw(
10321 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 }
10323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325}
10326
10327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010328RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010329 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330 ASSERT(args.length() == 1);
10331
10332 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010333 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010334 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10335 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010336 if (!maybe_result->ToObject(&result)) return maybe_result;
10337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338
10339 // Count all frames which are relevant to debugging stack trace.
10340 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010342 if (id == StackFrame::NO_ID) {
10343 // If there is no JavaScript stack frame count is 0.
10344 return Smi::FromInt(0);
10345 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010346
10347 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10348 n += it.frame()->GetInlineCount();
10349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 return Smi::FromInt(n);
10351}
10352
10353
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010354class FrameInspector {
10355 public:
10356 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010357 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010358 Isolate* isolate)
10359 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10360 // Calculate the deoptimized frame.
10361 if (frame->is_optimized()) {
10362 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010363 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010364 }
10365 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010366 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010367 is_optimized_ = frame_->is_optimized();
10368 }
10369
10370 ~FrameInspector() {
10371 // Get rid of the calculated deoptimized frame if any.
10372 if (deoptimized_frame_ != NULL) {
10373 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10374 isolate_);
10375 }
10376 }
10377
10378 int GetParametersCount() {
10379 return is_optimized_
10380 ? deoptimized_frame_->parameters_count()
10381 : frame_->ComputeParametersCount();
10382 }
10383 int expression_count() { return deoptimized_frame_->expression_count(); }
10384 Object* GetFunction() {
10385 return is_optimized_
10386 ? deoptimized_frame_->GetFunction()
10387 : frame_->function();
10388 }
10389 Object* GetParameter(int index) {
10390 return is_optimized_
10391 ? deoptimized_frame_->GetParameter(index)
10392 : frame_->GetParameter(index);
10393 }
10394 Object* GetExpression(int index) {
10395 return is_optimized_
10396 ? deoptimized_frame_->GetExpression(index)
10397 : frame_->GetExpression(index);
10398 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010399 int GetSourcePosition() {
10400 return is_optimized_
10401 ? deoptimized_frame_->GetSourcePosition()
10402 : frame_->LookupCode()->SourcePosition(frame_->pc());
10403 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010404 bool IsConstructor() {
10405 return is_optimized_ && !is_bottommost_
10406 ? deoptimized_frame_->HasConstructStub()
10407 : frame_->IsConstructor();
10408 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010409
10410 // To inspect all the provided arguments the frame might need to be
10411 // replaced with the arguments frame.
10412 void SetArgumentsFrame(JavaScriptFrame* frame) {
10413 ASSERT(has_adapted_arguments_);
10414 frame_ = frame;
10415 is_optimized_ = frame_->is_optimized();
10416 ASSERT(!is_optimized_);
10417 }
10418
10419 private:
10420 JavaScriptFrame* frame_;
10421 DeoptimizedFrameInfo* deoptimized_frame_;
10422 Isolate* isolate_;
10423 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010424 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010425 bool has_adapted_arguments_;
10426
10427 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10428};
10429
10430
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010431static const int kFrameDetailsFrameIdIndex = 0;
10432static const int kFrameDetailsReceiverIndex = 1;
10433static const int kFrameDetailsFunctionIndex = 2;
10434static const int kFrameDetailsArgumentCountIndex = 3;
10435static const int kFrameDetailsLocalCountIndex = 4;
10436static const int kFrameDetailsSourcePositionIndex = 5;
10437static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010438static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010439static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010440static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010442
10443static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10444 JavaScriptFrame* frame) {
10445 SaveContext* save = isolate->save_context();
10446 while (save != NULL && !save->IsBelowFrame(frame)) {
10447 save = save->prev();
10448 }
10449 ASSERT(save != NULL);
10450 return save;
10451}
10452
10453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010454// Return an array with frame details
10455// args[0]: number: break id
10456// args[1]: number: frame index
10457//
10458// The array returned contains the following information:
10459// 0: Frame id
10460// 1: Receiver
10461// 2: Function
10462// 3: Argument count
10463// 4: Local count
10464// 5: Source position
10465// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010466// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010467// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010468// Arguments name, value
10469// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010470// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010471RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 ASSERT(args.length() == 2);
10474
10475 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010476 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010477 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10478 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010479 if (!maybe_check->ToObject(&check)) return maybe_check;
10480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010482 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483
10484 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010485 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010486 if (id == StackFrame::NO_ID) {
10487 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010488 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010489 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010492 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010494 if (index < count + it.frame()->GetInlineCount()) break;
10495 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010499 bool is_optimized = it.frame()->is_optimized();
10500
10501 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10502 if (is_optimized) {
10503 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010504 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010505 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010506 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010507
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 // Traverse the saved contexts chain to find the active context for the
10509 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010510 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511
10512 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010513 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010515 // Find source position in unoptimized code.
10516 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517
ulan@chromium.org967e2702012-02-28 09:49:15 +000010518 // Check for constructor frame.
10519 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010521 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010522 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010523 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010524 Handle<ScopeInfo> scope_info(shared->scope_info());
10525 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 // Get the locals names and values into a temporary array.
10528 //
10529 // TODO(1240907): Hide compiler-introduced stack variables
10530 // (e.g. .result)? For users of the debugger, they will probably be
10531 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010532 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010533 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010535 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010536 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010537 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010538 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010539 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010540 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010541 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010542 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010543 // Get the context containing declarations.
10544 Handle<Context> context(
10545 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010546 for (; i < scope_info->LocalCount(); ++i) {
10547 Handle<String> name(scope_info->LocalName(i));
10548 VariableMode mode;
10549 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010550 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010551 locals->set(i * 2 + 1, context->get(
10552 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 }
10554 }
10555
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010556 // Check whether this frame is positioned at return. If not top
10557 // frame or if the frame is optimized it cannot be at a return.
10558 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010559 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010561 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010562
10563 // If positioned just before return find the value to be returned and add it
10564 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010566 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010567 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010568 Address internal_frame_sp = NULL;
10569 while (!it2.done()) {
10570 if (it2.frame()->is_internal()) {
10571 internal_frame_sp = it2.frame()->sp();
10572 } else {
10573 if (it2.frame()->is_java_script()) {
10574 if (it2.frame()->id() == it.frame()->id()) {
10575 // The internal frame just before the JavaScript frame contains the
10576 // value to return on top. A debug break at return will create an
10577 // internal frame to store the return value (eax/rax/r0) before
10578 // entering the debug break exit frame.
10579 if (internal_frame_sp != NULL) {
10580 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581 Handle<Object>(Memory::Object_at(internal_frame_sp),
10582 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010583 break;
10584 }
10585 }
10586 }
10587
10588 // Indicate that the previous frame was not an internal frame.
10589 internal_frame_sp = NULL;
10590 }
10591 it2.Advance();
10592 }
10593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
10595 // Now advance to the arguments adapter frame (if any). It contains all
10596 // the provided parameters whereas the function frame always have the number
10597 // of arguments matching the functions parameters. The rest of the
10598 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010599 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010600 it.AdvanceToArgumentsFrame();
10601 frame_inspector.SetArgumentsFrame(it.frame());
10602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603
10604 // Find the number of arguments to fill. At least fill the number of
10605 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010606 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010607 if (argument_count < frame_inspector.GetParametersCount()) {
10608 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 }
10610
10611 // Calculate the size of the result.
10612 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010613 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010614 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010615 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616
10617 // Add the frame id.
10618 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10619
10620 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010621 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622
10623 // Add the arguments count.
10624 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10625
10626 // Add the locals count
10627 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010628 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629
10630 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010631 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010632 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10633 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010634 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635 }
10636
10637 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010640 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010641 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010642
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010643 // Add flags to indicate information on whether this frame is
10644 // bit 0: invoked in the debugger context.
10645 // bit 1: optimized frame.
10646 // bit 2: inlined in optimized frame
10647 int flags = 0;
10648 if (*save->context() == *isolate->debug()->debug_context()) {
10649 flags |= 1 << 0;
10650 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010651 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010652 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010653 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010654 }
10655 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656
10657 // Fill the dynamic part.
10658 int details_index = kFrameDetailsFirstDynamicIndex;
10659
10660 // Add arguments name and value.
10661 for (int i = 0; i < argument_count; i++) {
10662 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010663 if (i < scope_info->ParameterCount()) {
10664 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010666 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 }
10668
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010669 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010670 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010671 // Get the value from the stack.
10672 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010674 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 }
10676 }
10677
10678 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010679 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 details->set(details_index++, locals->get(i));
10681 }
10682
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010683 // Add the value being returned.
10684 if (at_return) {
10685 details->set(details_index++, *return_value);
10686 }
10687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010688 // Add the receiver (same as in function frame).
10689 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10690 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010691 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010692 if (!receiver->IsJSObject() &&
10693 shared->is_classic_mode() &&
10694 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010695 // If the receiver is not a JSObject and the function is not a
10696 // builtin or strict-mode we have hit an optimization where a
10697 // value object is not converted into a wrapped JS objects. To
10698 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 // by creating correct wrapper object based on the calling frame's
10700 // global context.
10701 it.Advance();
10702 Handle<Context> calling_frames_global_context(
10703 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010704 receiver =
10705 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 }
10707 details->set(kFrameDetailsReceiverIndex, *receiver);
10708
10709 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010710 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711}
10712
10713
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010714// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010715static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010717 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010718 Handle<Context> context,
10719 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010720 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010721 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10722 VariableMode mode;
10723 InitializationFlag init_flag;
10724 int context_index = scope_info->ContextSlotIndex(
10725 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010726
whesse@chromium.org7b260152011-06-20 15:33:18 +000010727 RETURN_IF_EMPTY_HANDLE_VALUE(
10728 isolate,
10729 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010730 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010731 Handle<Object>(context->get(context_index), isolate),
10732 NONE,
10733 kNonStrictMode),
10734 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010735 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010736
10737 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010738}
10739
10740
10741// Create a plain JSObject which materializes the local scope for the specified
10742// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010743static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010744 Isolate* isolate,
10745 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010746 FrameInspector* frame_inspector) {
10747 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010748 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010749 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010750
10751 // Allocate and initialize a JSObject with all the arguments, stack locals
10752 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 Handle<JSObject> local_scope =
10754 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010755
10756 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010757 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010758 Handle<Object> value(
10759 i < frame_inspector->GetParametersCount() ?
10760 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10761
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010762 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010764 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010765 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010766 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010767 NONE,
10768 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010769 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010770 }
10771
10772 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010773 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010774 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010775 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010776 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010777 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010778 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010779 NONE,
10780 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010781 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010782 }
10783
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010784 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010785 // Third fill all context locals.
10786 Handle<Context> frame_context(Context::cast(frame->context()));
10787 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010788 if (!CopyContextLocalsToScopeObject(
10789 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010790 return Handle<JSObject>();
10791 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010792
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010793 // Finally copy any properties from the function context extension.
10794 // These will be variables introduced by eval.
10795 if (function_context->closure() == *function) {
10796 if (function_context->has_extension() &&
10797 !function_context->IsGlobalContext()) {
10798 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010799 bool threw = false;
10800 Handle<FixedArray> keys =
10801 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10802 if (threw) return Handle<JSObject>();
10803
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010804 for (int i = 0; i < keys->length(); i++) {
10805 // Names of variables introduced by eval are strings.
10806 ASSERT(keys->get(i)->IsString());
10807 Handle<String> key(String::cast(keys->get(i)));
10808 RETURN_IF_EMPTY_HANDLE_VALUE(
10809 isolate,
10810 SetProperty(local_scope,
10811 key,
10812 GetProperty(ext, key),
10813 NONE,
10814 kNonStrictMode),
10815 Handle<JSObject>());
10816 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010817 }
10818 }
10819 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010820
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010821 return local_scope;
10822}
10823
10824
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010825static Handle<JSObject> MaterializeLocalScope(
10826 Isolate* isolate,
10827 JavaScriptFrame* frame,
10828 int inlined_jsframe_index) {
10829 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10830 return MaterializeLocalScopeWithFrameInspector(isolate,
10831 frame,
10832 &frame_inspector);
10833}
10834
10835
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010836// Create a plain JSObject which materializes the closure content for the
10837// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10839 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010840 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010841
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010842 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010843 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010844
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010845 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010846 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 Handle<JSObject> closure_scope =
10848 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010849
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010850 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010851 if (!CopyContextLocalsToScopeObject(
10852 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010853 return Handle<JSObject>();
10854 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010855
10856 // Finally copy any properties from the function context extension. This will
10857 // be variables introduced by eval.
10858 if (context->has_extension()) {
10859 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010860 bool threw = false;
10861 Handle<FixedArray> keys =
10862 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10863 if (threw) return Handle<JSObject>();
10864
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010865 for (int i = 0; i < keys->length(); i++) {
10866 // Names of variables introduced by eval are strings.
10867 ASSERT(keys->get(i)->IsString());
10868 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010869 RETURN_IF_EMPTY_HANDLE_VALUE(
10870 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010871 SetProperty(closure_scope,
10872 key,
10873 GetProperty(ext, key),
10874 NONE,
10875 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010876 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010877 }
10878 }
10879
10880 return closure_scope;
10881}
10882
10883
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010884// Create a plain JSObject which materializes the scope for the specified
10885// catch context.
10886static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10887 Handle<Context> context) {
10888 ASSERT(context->IsCatchContext());
10889 Handle<String> name(String::cast(context->extension()));
10890 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10891 Handle<JSObject> catch_scope =
10892 isolate->factory()->NewJSObject(isolate->object_function());
10893 RETURN_IF_EMPTY_HANDLE_VALUE(
10894 isolate,
10895 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10896 Handle<JSObject>());
10897 return catch_scope;
10898}
10899
10900
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010901// Create a plain JSObject which materializes the block scope for the specified
10902// block context.
10903static Handle<JSObject> MaterializeBlockScope(
10904 Isolate* isolate,
10905 Handle<Context> context) {
10906 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010907 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010908
10909 // Allocate and initialize a JSObject with all the arguments, stack locals
10910 // heap locals and extension properties of the debugged function.
10911 Handle<JSObject> block_scope =
10912 isolate->factory()->NewJSObject(isolate->object_function());
10913
10914 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010915 if (!CopyContextLocalsToScopeObject(
10916 isolate, scope_info, context, block_scope)) {
10917 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010918 }
10919
10920 return block_scope;
10921}
10922
10923
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010924// Create a plain JSObject which materializes the module scope for the specified
10925// module context.
10926static Handle<JSObject> MaterializeModuleScope(
10927 Isolate* isolate,
10928 Handle<Context> context) {
10929 ASSERT(context->IsModuleContext());
10930 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10931
10932 // Allocate and initialize a JSObject with all the members of the debugged
10933 // module.
10934 Handle<JSObject> module_scope =
10935 isolate->factory()->NewJSObject(isolate->object_function());
10936
10937 // Fill all context locals.
10938 if (!CopyContextLocalsToScopeObject(
10939 isolate, scope_info, context, module_scope)) {
10940 return Handle<JSObject>();
10941 }
10942
10943 return module_scope;
10944}
10945
10946
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010947// Iterate over the actual scopes visible from a stack frame. The iteration
10948// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010949// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010950// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010951class ScopeIterator {
10952 public:
10953 enum ScopeType {
10954 ScopeTypeGlobal = 0,
10955 ScopeTypeLocal,
10956 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010957 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010958 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010959 ScopeTypeBlock,
10960 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010961 };
10962
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010963 ScopeIterator(Isolate* isolate,
10964 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010965 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010966 : isolate_(isolate),
10967 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010968 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010969 function_(JSFunction::cast(frame->function())),
10970 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010971 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010972
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010973 // Catch the case when the debugger stops in an internal function.
10974 Handle<SharedFunctionInfo> shared_info(function_->shared());
10975 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10976 if (shared_info->script() == isolate->heap()->undefined_value()) {
10977 while (context_->closure() == *function_) {
10978 context_ = Handle<Context>(context_->previous(), isolate_);
10979 }
10980 return;
10981 }
10982
10983 // Get the debug info (create it if it does not exist).
10984 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10985 // Return if ensuring debug info failed.
10986 return;
10987 }
10988 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10989
10990 // Find the break point where execution has stopped.
10991 BreakLocationIterator break_location_iterator(debug_info,
10992 ALL_BREAK_LOCATIONS);
10993 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10994 if (break_location_iterator.IsExit()) {
10995 // We are within the return sequence. At the momemt it is not possible to
10996 // get a source position which is consistent with the current scope chain.
10997 // Thus all nested with, catch and block contexts are skipped and we only
10998 // provide the function scope.
10999 if (scope_info->HasContext()) {
11000 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11001 } else {
11002 while (context_->closure() == *function_) {
11003 context_ = Handle<Context>(context_->previous(), isolate_);
11004 }
11005 }
11006 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11007 } else {
11008 // Reparse the code and analyze the scopes.
11009 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11010 Handle<Script> script(Script::cast(shared_info->script()));
11011 Scope* scope = NULL;
11012
11013 // Check whether we are in global, eval or function code.
11014 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11015 if (scope_info->Type() != FUNCTION_SCOPE) {
11016 // Global or eval code.
11017 CompilationInfo info(script);
11018 if (scope_info->Type() == GLOBAL_SCOPE) {
11019 info.MarkAsGlobal();
11020 } else {
11021 ASSERT(scope_info->Type() == EVAL_SCOPE);
11022 info.MarkAsEval();
11023 info.SetCallingContext(Handle<Context>(function_->context()));
11024 }
11025 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11026 scope = info.function()->scope();
11027 }
11028 } else {
11029 // Function code
11030 CompilationInfo info(shared_info);
11031 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11032 scope = info.function()->scope();
11033 }
11034 }
11035
11036 // Retrieve the scope chain for the current position.
11037 if (scope != NULL) {
11038 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11039 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11040 } else {
11041 // A failed reparse indicates that the preparser has diverged from the
11042 // parser or that the preparse data given to the initial parse has been
11043 // faulty. We fail in debug mode but in release mode we only provide the
11044 // information we get from the context chain but nothing about
11045 // completely stack allocated scopes or stack allocated locals.
11046 UNREACHABLE();
11047 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011048 }
11049 }
11050
11051 // More scopes?
11052 bool Done() { return context_.is_null(); }
11053
11054 // Move to the next scope.
11055 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011056 ScopeType scope_type = Type();
11057 if (scope_type == ScopeTypeGlobal) {
11058 // The global scope is always the last in the chain.
11059 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011060 context_ = Handle<Context>();
11061 return;
11062 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011063 if (nested_scope_chain_.is_empty()) {
11064 context_ = Handle<Context>(context_->previous(), isolate_);
11065 } else {
11066 if (nested_scope_chain_.last()->HasContext()) {
11067 ASSERT(context_->previous() != NULL);
11068 context_ = Handle<Context>(context_->previous(), isolate_);
11069 }
11070 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011071 }
11072 }
11073
11074 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011075 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011076 if (!nested_scope_chain_.is_empty()) {
11077 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11078 switch (scope_info->Type()) {
11079 case FUNCTION_SCOPE:
11080 ASSERT(context_->IsFunctionContext() ||
11081 !scope_info->HasContext());
11082 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011083 case MODULE_SCOPE:
11084 ASSERT(context_->IsModuleContext());
11085 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011086 case GLOBAL_SCOPE:
11087 ASSERT(context_->IsGlobalContext());
11088 return ScopeTypeGlobal;
11089 case WITH_SCOPE:
11090 ASSERT(context_->IsWithContext());
11091 return ScopeTypeWith;
11092 case CATCH_SCOPE:
11093 ASSERT(context_->IsCatchContext());
11094 return ScopeTypeCatch;
11095 case BLOCK_SCOPE:
11096 ASSERT(!scope_info->HasContext() ||
11097 context_->IsBlockContext());
11098 return ScopeTypeBlock;
11099 case EVAL_SCOPE:
11100 UNREACHABLE();
11101 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102 }
11103 if (context_->IsGlobalContext()) {
11104 ASSERT(context_->global()->IsGlobalObject());
11105 return ScopeTypeGlobal;
11106 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011107 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011108 return ScopeTypeClosure;
11109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011110 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011111 return ScopeTypeCatch;
11112 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011113 if (context_->IsBlockContext()) {
11114 return ScopeTypeBlock;
11115 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011116 if (context_->IsModuleContext()) {
11117 return ScopeTypeModule;
11118 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011119 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120 return ScopeTypeWith;
11121 }
11122
11123 // Return the JavaScript object with the content of the current scope.
11124 Handle<JSObject> ScopeObject() {
11125 switch (Type()) {
11126 case ScopeIterator::ScopeTypeGlobal:
11127 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011128 case ScopeIterator::ScopeTypeLocal:
11129 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011130 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011131 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011132 case ScopeIterator::ScopeTypeWith:
11133 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011134 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11135 case ScopeIterator::ScopeTypeCatch:
11136 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011137 case ScopeIterator::ScopeTypeClosure:
11138 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011139 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011140 case ScopeIterator::ScopeTypeBlock:
11141 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011142 case ScopeIterator::ScopeTypeModule:
11143 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 }
11145 UNREACHABLE();
11146 return Handle<JSObject>();
11147 }
11148
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011149 Handle<ScopeInfo> CurrentScopeInfo() {
11150 if (!nested_scope_chain_.is_empty()) {
11151 return nested_scope_chain_.last();
11152 } else if (context_->IsBlockContext()) {
11153 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11154 } else if (context_->IsFunctionContext()) {
11155 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11156 }
11157 return Handle<ScopeInfo>::null();
11158 }
11159
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011160 // Return the context for this scope. For the local context there might not
11161 // be an actual context.
11162 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011163 if (Type() == ScopeTypeGlobal ||
11164 nested_scope_chain_.is_empty()) {
11165 return context_;
11166 } else if (nested_scope_chain_.last()->HasContext()) {
11167 return context_;
11168 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011169 return Handle<Context>();
11170 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011171 }
11172
11173#ifdef DEBUG
11174 // Debug print of the content of the current scope.
11175 void DebugPrint() {
11176 switch (Type()) {
11177 case ScopeIterator::ScopeTypeGlobal:
11178 PrintF("Global:\n");
11179 CurrentContext()->Print();
11180 break;
11181
11182 case ScopeIterator::ScopeTypeLocal: {
11183 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011184 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185 if (!CurrentContext().is_null()) {
11186 CurrentContext()->Print();
11187 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011188 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 if (extension->IsJSContextExtensionObject()) {
11190 extension->Print();
11191 }
11192 }
11193 }
11194 break;
11195 }
11196
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011197 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011198 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011199 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011200 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011201
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011202 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011203 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011204 CurrentContext()->extension()->Print();
11205 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011206 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011207
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011208 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209 PrintF("Closure:\n");
11210 CurrentContext()->Print();
11211 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011212 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011213 if (extension->IsJSContextExtensionObject()) {
11214 extension->Print();
11215 }
11216 }
11217 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011218
11219 default:
11220 UNREACHABLE();
11221 }
11222 PrintF("\n");
11223 }
11224#endif
11225
11226 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011227 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011229 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230 Handle<JSFunction> function_;
11231 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011232 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011233
11234 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11235};
11236
11237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011238RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011239 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240 ASSERT(args.length() == 2);
11241
11242 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011243 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011244 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11245 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011246 if (!maybe_check->ToObject(&check)) return maybe_check;
11247 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011248 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011249
11250 // Get the frame where the debugging is performed.
11251 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011252 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011253 JavaScriptFrame* frame = it.frame();
11254
11255 // Count the visible scopes.
11256 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011257 for (ScopeIterator it(isolate, frame, 0);
11258 !it.Done();
11259 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011260 n++;
11261 }
11262
11263 return Smi::FromInt(n);
11264}
11265
11266
11267static const int kScopeDetailsTypeIndex = 0;
11268static const int kScopeDetailsObjectIndex = 1;
11269static const int kScopeDetailsSize = 2;
11270
11271// Return an array with scope details
11272// args[0]: number: break id
11273// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011274// args[2]: number: inlined frame index
11275// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011276//
11277// The array returned contains the following information:
11278// 0: Scope type
11279// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011280RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011281 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011282 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011283
11284 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011285 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011286 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11287 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011288 if (!maybe_check->ToObject(&check)) return maybe_check;
11289 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011290 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011291 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011292 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011293
11294 // Get the frame where the debugging is performed.
11295 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011296 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011297 JavaScriptFrame* frame = frame_it.frame();
11298
11299 // Find the requested scope.
11300 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011301 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011302 for (; !it.Done() && n < index; it.Next()) {
11303 n++;
11304 }
11305 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011306 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011307 }
11308
11309 // Calculate the size of the result.
11310 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011311 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011312
11313 // Fill in scope details.
11314 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011315 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011316 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011317 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011318
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011319 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011320}
11321
11322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011323RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011324 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011325 ASSERT(args.length() == 0);
11326
11327#ifdef DEBUG
11328 // Print the scopes for the top frame.
11329 StackFrameLocator locator;
11330 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011331 for (ScopeIterator it(isolate, frame, 0);
11332 !it.Done();
11333 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011334 it.DebugPrint();
11335 }
11336#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011338}
11339
11340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011341RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011342 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011343 ASSERT(args.length() == 1);
11344
11345 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011346 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011347 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11348 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011349 if (!maybe_result->ToObject(&result)) return maybe_result;
11350 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011351
11352 // Count all archived V8 threads.
11353 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011354 for (ThreadState* thread =
11355 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011356 thread != NULL;
11357 thread = thread->Next()) {
11358 n++;
11359 }
11360
11361 // Total number of threads is current thread and archived threads.
11362 return Smi::FromInt(n + 1);
11363}
11364
11365
11366static const int kThreadDetailsCurrentThreadIndex = 0;
11367static const int kThreadDetailsThreadIdIndex = 1;
11368static const int kThreadDetailsSize = 2;
11369
11370// Return an array with thread details
11371// args[0]: number: break id
11372// args[1]: number: thread index
11373//
11374// The array returned contains the following information:
11375// 0: Is current thread?
11376// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011377RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011378 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011379 ASSERT(args.length() == 2);
11380
11381 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011382 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011383 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11384 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011385 if (!maybe_check->ToObject(&check)) return maybe_check;
11386 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011387 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11388
11389 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011390 Handle<FixedArray> details =
11391 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011392
11393 // Thread index 0 is current thread.
11394 if (index == 0) {
11395 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011396 details->set(kThreadDetailsCurrentThreadIndex,
11397 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011398 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011399 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011400 } else {
11401 // Find the thread with the requested index.
11402 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 ThreadState* thread =
11404 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011405 while (index != n && thread != NULL) {
11406 thread = thread->Next();
11407 n++;
11408 }
11409 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011410 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011411 }
11412
11413 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011414 details->set(kThreadDetailsCurrentThreadIndex,
11415 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011416 details->set(kThreadDetailsThreadIdIndex,
11417 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011418 }
11419
11420 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011422}
11423
11424
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011425// Sets the disable break state
11426// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011427RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011428 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011429 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011430 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011431 isolate->debug()->set_disable_break(disable_break);
11432 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011433}
11434
11435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011436RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011438 ASSERT(args.length() == 1);
11439
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011440 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011441 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011442 // Find the number of break points
11443 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011445 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011446 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011447 Handle<FixedArray>::cast(break_locations));
11448}
11449
11450
11451// Set a break point in a function
11452// args[0]: function
11453// args[1]: number: break source position (within the function source)
11454// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011455RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011457 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011458 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011459 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011460 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11461 RUNTIME_ASSERT(source_position >= 0);
11462 Handle<Object> break_point_object_arg = args.at<Object>(2);
11463
11464 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011465 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11466 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011467
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011468 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011469}
11470
11471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011472Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11473 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011474 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011475 // Iterate the heap looking for SharedFunctionInfo generated from the
11476 // script. The inner most SharedFunctionInfo containing the source position
11477 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011478 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011479 // which is found is not compiled it is compiled and the heap is iterated
11480 // again as the compilation might create inner functions from the newly
11481 // compiled function and the actual requested break point might be in one of
11482 // these functions.
11483 bool done = false;
11484 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011485 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011486 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011487 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011488 { // Extra scope for iterator and no-allocation.
11489 isolate->heap()->EnsureHeapIsIterable();
11490 AssertNoAllocation no_alloc_during_heap_iteration;
11491 HeapIterator iterator;
11492 for (HeapObject* obj = iterator.next();
11493 obj != NULL; obj = iterator.next()) {
11494 if (obj->IsSharedFunctionInfo()) {
11495 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11496 if (shared->script() == *script) {
11497 // If the SharedFunctionInfo found has the requested script data and
11498 // contains the source position it is a candidate.
11499 int start_position = shared->function_token_position();
11500 if (start_position == RelocInfo::kNoPosition) {
11501 start_position = shared->start_position();
11502 }
11503 if (start_position <= position &&
11504 position <= shared->end_position()) {
11505 // If there is no candidate or this function is within the current
11506 // candidate this is the new candidate.
11507 if (target.is_null()) {
11508 target_start_position = start_position;
11509 target = shared;
11510 } else {
11511 if (target_start_position == start_position &&
11512 shared->end_position() == target->end_position()) {
11513 // If a top-level function contain only one function
11514 // declartion the source for the top-level and the
11515 // function is the same. In that case prefer the non
11516 // top-level function.
11517 if (!shared->is_toplevel()) {
11518 target_start_position = start_position;
11519 target = shared;
11520 }
11521 } else if (target_start_position <= start_position &&
11522 shared->end_position() <= target->end_position()) {
11523 // This containment check includes equality as a function
11524 // inside a top-level function can share either start or end
11525 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011526 target_start_position = start_position;
11527 target = shared;
11528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529 }
11530 }
11531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011532 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011533 } // End for loop.
11534 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011536 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011537 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538 }
11539
11540 // If the candidate found is compiled we are done. NOTE: when lazy
11541 // compilation of inner functions is introduced some additional checking
11542 // needs to be done here to compile inner functions.
11543 done = target->is_compiled();
11544 if (!done) {
11545 // If the candidate is not compiled compile it to reveal any inner
11546 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011547 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011548 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011549 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011550
11551 return *target;
11552}
11553
11554
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011555// Changes the state of a break point in a script and returns source position
11556// where break point was set. NOTE: Regarding performance see the NOTE for
11557// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558// args[0]: script to set break point in
11559// args[1]: number: break source position (within the script source)
11560// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011561RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011564 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011565 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11566 RUNTIME_ASSERT(source_position >= 0);
11567 Handle<Object> break_point_object_arg = args.at<Object>(2);
11568
11569 // Get the script from the script wrapper.
11570 RUNTIME_ASSERT(wrapper->value()->IsScript());
11571 Handle<Script> script(Script::cast(wrapper->value()));
11572
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011573 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575 if (!result->IsUndefined()) {
11576 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11577 // Find position within function. The script position might be before the
11578 // source position of the first function.
11579 int position;
11580 if (shared->start_position() > source_position) {
11581 position = 0;
11582 } else {
11583 position = source_position - shared->start_position();
11584 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011586 position += shared->start_position();
11587 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011589 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011590}
11591
11592
11593// Clear a break point
11594// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011595RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011596 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011597 ASSERT(args.length() == 1);
11598 Handle<Object> break_point_object_arg = args.at<Object>(0);
11599
11600 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011601 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011603 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011604}
11605
11606
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011607// Change the state of break on exceptions.
11608// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11609// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011610RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011612 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011613 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011614 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011615
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011616 // If the number doesn't match an enum value, the ChangeBreakOnException
11617 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618 ExceptionBreakType type =
11619 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011620 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 isolate->debug()->ChangeBreakOnException(type, enable);
11622 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011623}
11624
11625
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011626// Returns the state of break on exceptions
11627// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011628RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011629 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011630 ASSERT(args.length() == 1);
11631 RUNTIME_ASSERT(args[0]->IsNumber());
11632
11633 ExceptionBreakType type =
11634 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011636 return Smi::FromInt(result);
11637}
11638
11639
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011640// Prepare for stepping
11641// args[0]: break id for checking execution state
11642// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011643// args[2]: number of times to perform the step, for step out it is the number
11644// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011645RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 ASSERT(args.length() == 3);
11648 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011649 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011650 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11651 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011652 if (!maybe_check->ToObject(&check)) return maybe_check;
11653 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011654 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
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 step action and check validity.
11659 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11660 if (step_action != StepIn &&
11661 step_action != StepNext &&
11662 step_action != StepOut &&
11663 step_action != StepInMin &&
11664 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011666 }
11667
11668 // Get the number of steps.
11669 int step_count = NumberToInt32(args[2]);
11670 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 }
11673
ager@chromium.orga1645e22009-09-09 19:27:10 +000011674 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011676
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011677 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11679 step_count);
11680 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681}
11682
11683
11684// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011685RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011686 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011687 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011688 isolate->debug()->ClearStepping();
11689 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690}
11691
11692
11693// Creates a copy of the with context chain. The copy of the context chain is
11694// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011695static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11696 Handle<JSFunction> function,
11697 Handle<Context> base,
11698 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011699 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011700 HandleScope scope(isolate);
11701 List<Handle<ScopeInfo> > scope_chain;
11702 List<Handle<Context> > context_chain;
11703
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011704 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011705 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11706 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11707 ASSERT(!it.Done());
11708 scope_chain.Add(it.CurrentScopeInfo());
11709 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011710 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011711
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011712 // At the end of the chain. Return the base context to link to.
11713 Handle<Context> context = base;
11714
11715 // Iteratively copy and or materialize the nested contexts.
11716 while (!scope_chain.is_empty()) {
11717 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11718 Handle<Context> current = context_chain.RemoveLast();
11719 ASSERT(!(scope_info->HasContext() & current.is_null()));
11720
11721 if (scope_info->Type() == CATCH_SCOPE) {
11722 Handle<String> name(String::cast(current->extension()));
11723 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11724 context =
11725 isolate->factory()->NewCatchContext(function,
11726 context,
11727 name,
11728 thrown_object);
11729 } else if (scope_info->Type() == BLOCK_SCOPE) {
11730 // Materialize the contents of the block scope into a JSObject.
11731 Handle<JSObject> block_scope_object =
11732 MaterializeBlockScope(isolate, current);
11733 if (block_scope_object.is_null()) {
11734 return Handle<Context>::null();
11735 }
11736 // Allocate a new function context for the debug evaluation and set the
11737 // extension object.
11738 Handle<Context> new_context =
11739 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11740 function);
11741 new_context->set_extension(*block_scope_object);
11742 new_context->set_previous(*context);
11743 context = new_context;
11744 } else {
11745 ASSERT(scope_info->Type() == WITH_SCOPE);
11746 ASSERT(current->IsWithContext());
11747 Handle<JSObject> extension(JSObject::cast(current->extension()));
11748 context =
11749 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011750 }
erikcorry0ad885c2011-11-21 13:51:57 +000011751 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011752
11753 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754}
11755
11756
11757// Helper function to find or create the arguments object for
11758// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759static Handle<Object> GetArgumentsObject(Isolate* isolate,
11760 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011761 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011762 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 Handle<Context> function_context) {
11764 // Try to find the value of 'arguments' to pass as parameter. If it is not
11765 // found (that is the debugged function does not reference 'arguments' and
11766 // does not support eval) then create an 'arguments' object.
11767 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011768 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011769 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011770 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 }
11773 }
11774
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011775 if (scope_info->HasHeapAllocatedLocals()) {
11776 VariableMode mode;
11777 InitializationFlag init_flag;
11778 index = scope_info->ContextSlotIndex(
11779 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011780 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782 }
11783 }
11784
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011785 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11786 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 Handle<JSObject> arguments =
11788 isolate->factory()->NewArgumentsObject(function, length);
11789 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011790
11791 AssertNoAllocation no_gc;
11792 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011793 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011794 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011795 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011796 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 return arguments;
11798}
11799
11800
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011801static const char kSourceStr[] =
11802 "(function(arguments,__source__){return eval(__source__);})";
11803
11804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011806// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011807// extension part has all the parameters and locals of the function on the
11808// stack frame. A function which calls eval with the code to evaluate is then
11809// compiled in this context and called in this context. As this context
11810// replaces the context of the function on the stack frame a new (empty)
11811// function is created as well to be used as the closure for the context.
11812// This function and the context acts as replacements for the function on the
11813// stack frame presenting the same view of the values of parameters and
11814// local variables as if the piece of JavaScript was evaluated at the point
11815// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011816RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011818
11819 // Check the execution state and decode arguments frame and source to be
11820 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011821 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011822 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011823 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11824 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011825 if (!maybe_check_result->ToObject(&check_result)) {
11826 return maybe_check_result;
11827 }
11828 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011829 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011830 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011831 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11832 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011833 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011834
11835 // Handle the processing of break.
11836 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837
11838 // Get the frame where the debugging is performed.
11839 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011840 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011842 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11843 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011844 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845
11846 // Traverse the saved contexts chain to find the active context for the
11847 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011848 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 SaveContext savex(isolate);
11851 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852
11853 // Create the (empty) function replacing the function on the stack frame for
11854 // the purpose of evaluating in the context created below. It is important
11855 // that this function does not describe any parameters and local variables
11856 // in the context. If it does then this will cause problems with the lookup
11857 // in Context::Lookup, where context slots for parameters and local variables
11858 // are looked at before the extension object.
11859 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11861 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862 go_between->set_context(function->context());
11863#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011864 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11865 ASSERT(go_between_scope_info->ParameterCount() == 0);
11866 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011867#endif
11868
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011869 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011870 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11871 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011873
11874 // Allocate a new context for the debug evaluation and set the extension
11875 // object build.
11876 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11878 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011879 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011881 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011882 Handle<Context> function_context;
11883 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011884 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011885 function_context = Handle<Context>(frame_context->declaration_context());
11886 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011887 context = CopyNestedScopeContextChain(isolate,
11888 go_between,
11889 context,
11890 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011891 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011892
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011893 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011894 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011895 context =
11896 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011897 }
11898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011899 // Wrap the evaluation statement in a new function compiled in the newly
11900 // created context. The function has one parameter which has to be called
11901 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011902 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011906 isolate->factory()->NewStringFromAscii(
11907 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011908
11909 // Currently, the eval code will be executed in non-strict mode,
11910 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011911 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011912 Compiler::CompileEval(function_source,
11913 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011914 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011915 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011916 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011917 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011919 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011920
11921 // Invoke the result of the compilation to get the evaluation function.
11922 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924 Handle<Object> evaluation_function =
11925 Execution::Call(compiled_function, receiver, 0, NULL,
11926 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011927 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011929 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011930 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011931 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011932 scope_info,
11933 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011934
11935 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011936 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011938 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11939 receiver,
11940 ARRAY_SIZE(argv),
11941 argv,
11942 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011943 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011944
11945 // Skip the global proxy as it has no properties and always delegates to the
11946 // real global object.
11947 if (result->IsJSGlobalProxy()) {
11948 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11949 }
11950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011951 return *result;
11952}
11953
11954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011955RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011956 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011957
11958 // Check the execution state and decode arguments frame and source to be
11959 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011960 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011961 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011962 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11963 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011964 if (!maybe_check_result->ToObject(&check_result)) {
11965 return maybe_check_result;
11966 }
11967 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011968 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11969 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011970 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011971
11972 // Handle the processing of break.
11973 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974
11975 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011976 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011977 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011978 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011979 top = top->prev();
11980 }
11981 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011982 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011983 }
11984
11985 // Get the global context now set to the top context from before the
11986 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011987 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011989 bool is_global = true;
11990
11991 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011992 // Create a new with context with the additional context information between
11993 // the context of the debugged function and the eval code to be executed.
11994 context = isolate->factory()->NewWithContext(
11995 Handle<JSFunction>(context->closure()),
11996 context,
11997 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011998 is_global = false;
11999 }
12000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012001 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012002 // Currently, the eval code will be executed in non-strict mode,
12003 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012004 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012005 Compiler::CompileEval(source,
12006 context,
12007 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012008 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012009 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012010 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012011 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012012 Handle<JSFunction>(
12013 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12014 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015
12016 // Invoke the result of the compilation to get the evaluation function.
12017 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019 Handle<Object> result =
12020 Execution::Call(compiled_function, receiver, 0, NULL,
12021 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012022 // Clear the oneshot breakpoints so that the debugger does not step further.
12023 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012024 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025 return *result;
12026}
12027
12028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012031 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012033 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012035
12036 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012037 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012038 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12039 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12040 // because using
12041 // instances->set(i, *GetScriptWrapper(script))
12042 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012043 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012044 Handle<JSValue> wrapper = GetScriptWrapper(script);
12045 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046 }
12047
12048 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012049 Handle<JSObject> result =
12050 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012051 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052 return *result;
12053}
12054
12055
12056// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012057static int DebugReferencedBy(HeapIterator* iterator,
12058 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012059 Object* instance_filter, int max_references,
12060 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 JSFunction* arguments_function) {
12062 NoHandleAllocation ha;
12063 AssertNoAllocation no_alloc;
12064
12065 // Iterate the heap.
12066 int count = 0;
12067 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012068 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012069 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012070 (max_references == 0 || count < max_references)) {
12071 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072 if (heap_obj->IsJSObject()) {
12073 // Skip context extension objects and argument arrays as these are
12074 // checked in the context of functions using them.
12075 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012076 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012077 obj->map()->constructor() == arguments_function) {
12078 continue;
12079 }
12080
12081 // Check if the JS object has a reference to the object looked for.
12082 if (obj->ReferencesObject(target)) {
12083 // Check instance filter if supplied. This is normally used to avoid
12084 // references from mirror objects (see Runtime_IsInPrototypeChain).
12085 if (!instance_filter->IsUndefined()) {
12086 Object* V = obj;
12087 while (true) {
12088 Object* prototype = V->GetPrototype();
12089 if (prototype->IsNull()) {
12090 break;
12091 }
12092 if (instance_filter == prototype) {
12093 obj = NULL; // Don't add this object.
12094 break;
12095 }
12096 V = prototype;
12097 }
12098 }
12099
12100 if (obj != NULL) {
12101 // Valid reference found add to instance array if supplied an update
12102 // count.
12103 if (instances != NULL && count < instances_size) {
12104 instances->set(count, obj);
12105 }
12106 last = obj;
12107 count++;
12108 }
12109 }
12110 }
12111 }
12112
12113 // Check for circular reference only. This can happen when the object is only
12114 // referenced from mirrors and has a circular reference in which case the
12115 // object is not really alive and would have been garbage collected if not
12116 // referenced from the mirror.
12117 if (count == 1 && last == target) {
12118 count = 0;
12119 }
12120
12121 // Return the number of referencing objects found.
12122 return count;
12123}
12124
12125
12126// Scan the heap for objects with direct references to an object
12127// args[0]: the object to find references to
12128// args[1]: constructor function for instances to exclude (Mirror)
12129// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012130RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131 ASSERT(args.length() == 3);
12132
12133 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012134 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12135 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012136 // The heap iterator reserves the right to do a GC to make the heap iterable.
12137 // Due to the GC above we know it won't need to do that, but it seems cleaner
12138 // to get the heap iterator constructed before we start having unprotected
12139 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140
12141 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012142 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 Object* instance_filter = args[1];
12144 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12145 instance_filter->IsJSObject());
12146 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12147 RUNTIME_ASSERT(max_references >= 0);
12148
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012149
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012150 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012152 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153 JSFunction* arguments_function =
12154 JSFunction::cast(arguments_boilerplate->map()->constructor());
12155
12156 // Get the number of referencing objects.
12157 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012158 HeapIterator heap_iterator;
12159 count = DebugReferencedBy(&heap_iterator,
12160 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012161 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012162
12163 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012164 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012165 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012166 if (!maybe_object->ToObject(&object)) return maybe_object;
12167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012168 FixedArray* instances = FixedArray::cast(object);
12169
12170 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012171 // AllocateFixedArray above does not make the heap non-iterable.
12172 ASSERT(HEAP->IsHeapIterable());
12173 HeapIterator heap_iterator2;
12174 count = DebugReferencedBy(&heap_iterator2,
12175 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012176 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177
12178 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012179 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012180 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012181 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012182 if (!maybe_result->ToObject(&result)) return maybe_result;
12183 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184}
12185
12186
12187// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012188static int DebugConstructedBy(HeapIterator* iterator,
12189 JSFunction* constructor,
12190 int max_references,
12191 FixedArray* instances,
12192 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012193 AssertNoAllocation no_alloc;
12194
12195 // Iterate the heap.
12196 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012197 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012198 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199 (max_references == 0 || count < max_references)) {
12200 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201 if (heap_obj->IsJSObject()) {
12202 JSObject* obj = JSObject::cast(heap_obj);
12203 if (obj->map()->constructor() == constructor) {
12204 // Valid reference found add to instance array if supplied an update
12205 // count.
12206 if (instances != NULL && count < instances_size) {
12207 instances->set(count, obj);
12208 }
12209 count++;
12210 }
12211 }
12212 }
12213
12214 // Return the number of referencing objects found.
12215 return count;
12216}
12217
12218
12219// Scan the heap for objects constructed by a specific function.
12220// args[0]: the constructor to find instances of
12221// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012222RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 ASSERT(args.length() == 2);
12224
12225 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012226 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12227 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012228
12229 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012230 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12232 RUNTIME_ASSERT(max_references >= 0);
12233
12234 // Get the number of referencing objects.
12235 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012236 HeapIterator heap_iterator;
12237 count = DebugConstructedBy(&heap_iterator,
12238 constructor,
12239 max_references,
12240 NULL,
12241 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242
12243 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012244 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012245 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012246 if (!maybe_object->ToObject(&object)) return maybe_object;
12247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248 FixedArray* instances = FixedArray::cast(object);
12249
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012250 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012252 HeapIterator heap_iterator2;
12253 count = DebugConstructedBy(&heap_iterator2,
12254 constructor,
12255 max_references,
12256 instances,
12257 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258
12259 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012260 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012261 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12262 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012263 if (!maybe_result->ToObject(&result)) return maybe_result;
12264 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012265 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012266}
12267
12268
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012269// Find the effective prototype object as returned by __proto__.
12270// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012271RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272 ASSERT(args.length() == 1);
12273
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012274 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012275
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012276 // Use the __proto__ accessor.
12277 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012278}
12279
12280
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012281// Patches script source (should be called upon BeforeCompile event).
12282RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12283 HandleScope scope(isolate);
12284 ASSERT(args.length() == 2);
12285
12286 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12287 Handle<String> source(String::cast(args[1]));
12288
12289 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12290 Handle<Script> script(Script::cast(script_wrapper->value()));
12291
12292 int compilation_state = Smi::cast(script->compilation_state())->value();
12293 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12294 script->set_source(*source);
12295
12296 return isolate->heap()->undefined_value();
12297}
12298
12299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012300RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012301 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012302 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012303 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304}
12305
12306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012307RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012308#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012309 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012310 ASSERT(args.length() == 1);
12311 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012312 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012313 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012314 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012315 return Failure::Exception();
12316 }
12317 func->code()->PrintLn();
12318#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012319 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012320}
ager@chromium.org9085a012009-05-11 19:22:57 +000012321
12322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012323RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012324#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012325 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012326 ASSERT(args.length() == 1);
12327 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012328 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012329 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012330 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012331 return Failure::Exception();
12332 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012333 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012334#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012335 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012336}
12337
12338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012339RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012340 NoHandleAllocation ha;
12341 ASSERT(args.length() == 1);
12342
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012343 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012344 return f->shared()->inferred_name();
12345}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012346
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012347
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012348static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12349 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012350 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012351 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012352 int counter = 0;
12353 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012354 for (HeapObject* obj = iterator->next();
12355 obj != NULL;
12356 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012357 ASSERT(obj != NULL);
12358 if (!obj->IsSharedFunctionInfo()) {
12359 continue;
12360 }
12361 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12362 if (shared->script() != script) {
12363 continue;
12364 }
12365 if (counter < buffer_size) {
12366 buffer->set(counter, shared);
12367 }
12368 counter++;
12369 }
12370 return counter;
12371}
12372
12373// For a script finds all SharedFunctionInfo's in the heap that points
12374// to this script. Returns JSArray of SharedFunctionInfo wrapped
12375// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012376RUNTIME_FUNCTION(MaybeObject*,
12377 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012378 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012380 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012381
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012382
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012383 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12384
12385 const int kBufferSize = 32;
12386
12387 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012388 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012389 int number;
12390 {
12391 isolate->heap()->EnsureHeapIsIterable();
12392 AssertNoAllocation no_allocations;
12393 HeapIterator heap_iterator;
12394 Script* scr = *script;
12395 FixedArray* arr = *array;
12396 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12397 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012398 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012399 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012400 isolate->heap()->EnsureHeapIsIterable();
12401 AssertNoAllocation no_allocations;
12402 HeapIterator heap_iterator;
12403 Script* scr = *script;
12404 FixedArray* arr = *array;
12405 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012406 }
12407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012408 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012409 result->set_length(Smi::FromInt(number));
12410
12411 LiveEdit::WrapSharedFunctionInfos(result);
12412
12413 return *result;
12414}
12415
12416// For a script calculates compilation information about all its functions.
12417// The script source is explicitly specified by the second argument.
12418// The source of the actual script is not used, however it is important that
12419// all generated code keeps references to this particular instance of script.
12420// Returns a JSArray of compilation infos. The array is ordered so that
12421// each function with all its descendant is always stored in a continues range
12422// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012423RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012424 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012425 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012426 CONVERT_ARG_CHECKED(JSValue, script, 0);
12427 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012428 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12429
12430 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012432 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012433 return Failure::Exception();
12434 }
12435
12436 return result;
12437}
12438
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012439// Changes the source of the script to a new_source.
12440// If old_script_name is provided (i.e. is a String), also creates a copy of
12441// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012442RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012443 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012444 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012445 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12446 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012447 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012448
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012449 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12450 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012451
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012452 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12453 new_source,
12454 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012455
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012456 if (old_script->IsScript()) {
12457 Handle<Script> script_handle(Script::cast(old_script));
12458 return *(GetScriptWrapper(script_handle));
12459 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012460 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012461 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012462}
12463
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012465RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012466 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012468 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012469 return LiveEdit::FunctionSourceUpdated(shared_info);
12470}
12471
12472
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012473// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012474RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012475 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012476 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012477 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12478 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012479
ager@chromium.orgac091b72010-05-05 07:34:42 +000012480 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012481}
12482
12483// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012484RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012485 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012486 HandleScope scope(isolate);
12487 Handle<Object> function_object(args[0], isolate);
12488 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012489
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012490 if (function_object->IsJSValue()) {
12491 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12492 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012493 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12494 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012496 }
12497
12498 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12499 } else {
12500 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12501 // and we check it in this function.
12502 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012505}
12506
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012507
12508// In a code of a parent function replaces original function as embedded object
12509// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012510RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012511 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012513
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012514 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12515 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12516 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012517
12518 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12519 subst_wrapper);
12520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012521 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012522}
12523
12524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012525// Updates positions of a shared function info (first parameter) according
12526// to script source change. Text change is described in second parameter as
12527// array of groups of 3 numbers:
12528// (change_begin, change_end, change_end_new_position).
12529// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012530RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012531 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012532 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012533 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12534 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012535
ager@chromium.orgac091b72010-05-05 07:34:42 +000012536 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012537}
12538
12539
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012540// For array of SharedFunctionInfo's (each wrapped in JSValue)
12541// checks that none of them have activations on stacks (of any thread).
12542// Returns array of the same length with corresponding results of
12543// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012544RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012545 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012547 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12548 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012549
ager@chromium.org357bf652010-04-12 11:30:10 +000012550 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012551}
12552
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012553// Compares 2 strings line-by-line, then token-wise and returns diff in form
12554// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12555// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012556RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012557 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012558 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012559 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12560 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012561
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012562 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012563}
12564
12565
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012566// A testing entry. Returns statement position which is the closest to
12567// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012568RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012569 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012570 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012571 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012572 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012574 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012575
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012576 if (code->kind() != Code::FUNCTION &&
12577 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012579 }
12580
12581 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012582 int closest_pc = 0;
12583 int distance = kMaxInt;
12584 while (!it.done()) {
12585 int statement_position = static_cast<int>(it.rinfo()->data());
12586 // Check if this break point is closer that what was previously found.
12587 if (source_position <= statement_position &&
12588 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012589 closest_pc =
12590 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012591 distance = statement_position - source_position;
12592 // Check whether we can't get any closer.
12593 if (distance == 0) break;
12594 }
12595 it.next();
12596 }
12597
12598 return Smi::FromInt(closest_pc);
12599}
12600
12601
ager@chromium.org357bf652010-04-12 11:30:10 +000012602// Calls specified function with or without entering the debugger.
12603// This is used in unit tests to run code as if debugger is entered or simply
12604// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012605RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012606 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012607 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012608 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12609 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012610
12611 Handle<Object> result;
12612 bool pending_exception;
12613 {
12614 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012615 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012616 &pending_exception);
12617 } else {
12618 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012619 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012620 &pending_exception);
12621 }
12622 }
12623 if (!pending_exception) {
12624 return *result;
12625 } else {
12626 return Failure::Exception();
12627 }
12628}
12629
12630
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012631// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012632RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012633 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012634 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012635 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12636 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012638}
12639
12640
12641// Performs a GC.
12642// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012643RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012644 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012646}
12647
12648
12649// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012650RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012651 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012652 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012653 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012654 }
12655 return Smi::FromInt(usage);
12656}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012657
12658
12659// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012660RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012661#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012663#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012664 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012665#endif
12666}
12667
12668
12669// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012670RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012671#ifdef LIVE_OBJECT_LIST
12672 return LiveObjectList::Capture();
12673#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012675#endif
12676}
12677
12678
12679// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012680RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012681#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012682 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012683 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012684 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012685#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012686 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012687#endif
12688}
12689
12690
12691// Generates the response to a debugger request for a dump of the objects
12692// contained in the difference between the captured live object lists
12693// specified by id1 and id2.
12694// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12695// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012696RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012697#ifdef LIVE_OBJECT_LIST
12698 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012699 CONVERT_SMI_ARG_CHECKED(id1, 0);
12700 CONVERT_SMI_ARG_CHECKED(id2, 1);
12701 CONVERT_SMI_ARG_CHECKED(start, 2);
12702 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012703 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012704 EnterDebugger enter_debugger;
12705 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12706#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012707 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012708#endif
12709}
12710
12711
12712// Gets the specified object as requested by the debugger.
12713// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012715#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012716 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012717 Object* result = LiveObjectList::GetObj(obj_id);
12718 return result;
12719#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012720 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012721#endif
12722}
12723
12724
12725// Gets the obj id for the specified address if valid.
12726// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012727RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012728#ifdef LIVE_OBJECT_LIST
12729 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012730 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012731 Object* result = LiveObjectList::GetObjId(address);
12732 return result;
12733#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012734 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012735#endif
12736}
12737
12738
12739// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012740RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012741#ifdef LIVE_OBJECT_LIST
12742 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012743 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012744 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12745 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12746 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12747 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012748 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012749
12750 Handle<JSObject> instance_filter;
12751 if (args[1]->IsJSObject()) {
12752 instance_filter = args.at<JSObject>(1);
12753 }
12754 bool verbose = false;
12755 if (args[2]->IsBoolean()) {
12756 verbose = args[2]->IsTrue();
12757 }
12758 int start = 0;
12759 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012760 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012761 }
12762 int limit = Smi::kMaxValue;
12763 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012764 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012765 }
12766
12767 return LiveObjectList::GetObjRetainers(obj_id,
12768 instance_filter,
12769 verbose,
12770 start,
12771 limit,
12772 filter_obj);
12773#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012774 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012775#endif
12776}
12777
12778
12779// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012780RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012781#ifdef LIVE_OBJECT_LIST
12782 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012783 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12784 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012785 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12786
12787 Handle<JSObject> instance_filter;
12788 if (args[2]->IsJSObject()) {
12789 instance_filter = args.at<JSObject>(2);
12790 }
12791
12792 Object* result =
12793 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12794 return result;
12795#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012796 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012797#endif
12798}
12799
12800
12801// Generates the response to a debugger request for a list of all
12802// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012803RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012804#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012805 CONVERT_SMI_ARG_CHECKED(start, 0);
12806 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012807 return LiveObjectList::Info(start, count);
12808#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012809 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012810#endif
12811}
12812
12813
12814// Gets a dump of the specified object as requested by the debugger.
12815// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012816RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012817#ifdef LIVE_OBJECT_LIST
12818 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012819 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012820 Object* result = LiveObjectList::PrintObj(obj_id);
12821 return result;
12822#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012823 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012824#endif
12825}
12826
12827
12828// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012829RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012830#ifdef LIVE_OBJECT_LIST
12831 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012832 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012833#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012835#endif
12836}
12837
12838
12839// Generates the response to a debugger request for a summary of the types
12840// of objects in the difference between the captured live object lists
12841// specified by id1 and id2.
12842// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12843// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012844RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012845#ifdef LIVE_OBJECT_LIST
12846 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012847 CONVERT_SMI_ARG_CHECKED(id1, 0);
12848 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012849 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012850
12851 EnterDebugger enter_debugger;
12852 return LiveObjectList::Summarize(id1, id2, filter_obj);
12853#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012854 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012855#endif
12856}
12857
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012858#endif // ENABLE_DEBUGGER_SUPPORT
12859
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012861RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012862 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012863 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012864 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012865}
12866
12867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012868RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012869 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012870 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012871 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012872}
12873
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012875// Finds the script object from the script data. NOTE: This operation uses
12876// heap traversal to find the function generated for the source position
12877// for the requested break point. For lazily compiled functions several heap
12878// traversals might be required rendering this operation as a rather slow
12879// operation. However for setting break points which is normally done through
12880// some kind of user interaction the performance is not crucial.
12881static Handle<Object> Runtime_GetScriptFromScriptName(
12882 Handle<String> script_name) {
12883 // Scan the heap for Script objects to find the script with the requested
12884 // script data.
12885 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012886 script_name->GetHeap()->EnsureHeapIsIterable();
12887 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012888 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012889 HeapObject* obj = NULL;
12890 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012891 // If a script is found check if it has the script data requested.
12892 if (obj->IsScript()) {
12893 if (Script::cast(obj)->name()->IsString()) {
12894 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12895 script = Handle<Script>(Script::cast(obj));
12896 }
12897 }
12898 }
12899 }
12900
12901 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012902 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012903
12904 // Return the script found.
12905 return GetScriptWrapper(script);
12906}
12907
12908
12909// Get the script object from script data. NOTE: Regarding performance
12910// see the NOTE for GetScriptFromScriptData.
12911// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012912RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012914
12915 ASSERT(args.length() == 1);
12916
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012917 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012918
12919 // Find the requested script.
12920 Handle<Object> result =
12921 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12922 return *result;
12923}
12924
12925
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012926// Determines whether the given stack frame should be displayed in
12927// a stack trace. The caller is the error constructor that asked
12928// for the stack trace to be collected. The first time a construct
12929// call to this function is encountered it is skipped. The seen_caller
12930// in/out parameter is used to remember if the caller has been seen
12931// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012932static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12933 Object* caller,
12934 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012935 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012936 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012937 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012938 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012939 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12940 Object* raw_fun = frame->function();
12941 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012942 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012943 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012944 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012945 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012946 *seen_caller = true;
12947 return false;
12948 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012949 // Skip all frames until we've seen the caller.
12950 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012951 // Also, skip non-visible built-in functions and any call with the builtins
12952 // object as receiver, so as to not reveal either the builtins object or
12953 // an internal function.
12954 // The --builtins-in-stack-traces command line flag allows including
12955 // internal call sites in the stack trace for debugging purposes.
12956 if (!FLAG_builtins_in_stack_traces) {
12957 JSFunction* fun = JSFunction::cast(raw_fun);
12958 if (frame->receiver()->IsJSBuiltinsObject() ||
12959 (fun->IsBuiltin() && !fun->shared()->native())) {
12960 return false;
12961 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012962 }
12963 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012964}
12965
12966
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012967// Collect the raw data for a stack trace. Returns an array of 4
12968// element segments each containing a receiver, function, code and
12969// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012970RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012971 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012972 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012973 Handle<Object> caller = args.at<Object>(1);
12974 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012976 HandleScope scope(isolate);
12977 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012978
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012979 limit = Max(limit, 0); // Ensure that limit is not negative.
12980 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012981 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012982 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012983
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012984 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012985 // If the caller parameter is a function we skip frames until we're
12986 // under it before starting to collect.
12987 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012988 int cursor = 0;
12989 int frames_seen = 0;
12990 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012991 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012992 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012993 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012994 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012995 // Set initial size to the maximum inlining level + 1 for the outermost
12996 // function.
12997 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012998 frame->Summarize(&frames);
12999 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013000 if (cursor + 4 > elements->length()) {
13001 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13002 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013003 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013004 for (int i = 0; i < cursor; i++) {
13005 new_elements->set(i, elements->get(i));
13006 }
13007 elements = new_elements;
13008 }
13009 ASSERT(cursor + 4 <= elements->length());
13010
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013011 Handle<Object> recv = frames[i].receiver();
13012 Handle<JSFunction> fun = frames[i].function();
13013 Handle<Code> code = frames[i].code();
13014 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013015 elements->set(cursor++, *recv);
13016 elements->set(cursor++, *fun);
13017 elements->set(cursor++, *code);
13018 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013019 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013020 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013021 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013022 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013023 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013024 // Capture and attach a more detailed stack trace if necessary.
13025 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013026 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013027 return *result;
13028}
13029
13030
ager@chromium.org3811b432009-10-28 14:53:37 +000013031// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013032RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013033 ASSERT_EQ(args.length(), 0);
13034
13035 NoHandleAllocation ha;
13036
13037 const char* version_string = v8::V8::GetVersion();
13038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013039 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13040 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013041}
13042
13043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013044RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013045 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013046 OS::PrintError("abort: %s\n",
13047 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013048 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013049 OS::Abort();
13050 UNREACHABLE();
13051 return NULL;
13052}
13053
13054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013055RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013056 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013057 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013058 Object* key = args[1];
13059
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013060 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013061 Object* o = cache->get(finger_index);
13062 if (o == key) {
13063 // The fastest case: hit the same place again.
13064 return cache->get(finger_index + 1);
13065 }
13066
13067 for (int i = finger_index - 2;
13068 i >= JSFunctionResultCache::kEntriesIndex;
13069 i -= 2) {
13070 o = cache->get(i);
13071 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013072 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013073 return cache->get(i + 1);
13074 }
13075 }
13076
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013077 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013078 ASSERT(size <= cache->length());
13079
13080 for (int i = size - 2; i > finger_index; i -= 2) {
13081 o = cache->get(i);
13082 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013083 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013084 return cache->get(i + 1);
13085 }
13086 }
13087
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013088 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013089 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013090
13091 Handle<JSFunctionResultCache> cache_handle(cache);
13092 Handle<Object> key_handle(key);
13093 Handle<Object> value;
13094 {
13095 Handle<JSFunction> factory(JSFunction::cast(
13096 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13097 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013098 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013099 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013100 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013101 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013102 value = Execution::Call(factory,
13103 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013104 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013105 argv,
13106 &pending_exception);
13107 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013108 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013109
13110#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013111 if (FLAG_verify_heap) {
13112 cache_handle->JSFunctionResultCacheVerify();
13113 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013114#endif
13115
13116 // Function invocation may have cleared the cache. Reread all the data.
13117 finger_index = cache_handle->finger_index();
13118 size = cache_handle->size();
13119
13120 // If we have spare room, put new data into it, otherwise evict post finger
13121 // entry which is likely to be the least recently used.
13122 int index = -1;
13123 if (size < cache_handle->length()) {
13124 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13125 index = size;
13126 } else {
13127 index = finger_index + JSFunctionResultCache::kEntrySize;
13128 if (index == cache_handle->length()) {
13129 index = JSFunctionResultCache::kEntriesIndex;
13130 }
13131 }
13132
13133 ASSERT(index % 2 == 0);
13134 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13135 ASSERT(index < cache_handle->length());
13136
13137 cache_handle->set(index, *key_handle);
13138 cache_handle->set(index + 1, *value);
13139 cache_handle->set_finger_index(index);
13140
13141#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013142 if (FLAG_verify_heap) {
13143 cache_handle->JSFunctionResultCacheVerify();
13144 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013145#endif
13146
13147 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013148}
13149
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013151RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013152 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013153 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13154 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013155 return *isolate->factory()->NewJSMessageObject(
13156 type,
13157 arguments,
13158 0,
13159 0,
13160 isolate->factory()->undefined_value(),
13161 isolate->factory()->undefined_value(),
13162 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013163}
13164
13165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013166RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013167 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013168 return message->type();
13169}
13170
13171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013172RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013173 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013174 return message->arguments();
13175}
13176
13177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013178RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013179 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013180 return Smi::FromInt(message->start_position());
13181}
13182
13183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013184RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013185 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013186 return message->script();
13187}
13188
13189
kasper.lund44510672008-07-25 07:37:58 +000013190#ifdef DEBUG
13191// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13192// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013193RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013194 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013195 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013196#define COUNT_ENTRY(Name, argc, ressize) + 1
13197 int entry_count = 0
13198 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13199 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13200 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13201#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013202 Factory* factory = isolate->factory();
13203 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013204 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013205 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013206#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013207 { \
13208 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013209 Handle<String> name; \
13210 /* Inline runtime functions have an underscore in front of the name. */ \
13211 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013212 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013213 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13214 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013215 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013216 Vector<const char>(#Name, StrLength(#Name))); \
13217 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013218 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013219 pair_elements->set(0, *name); \
13220 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013221 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013222 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013223 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013224 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013225 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013226 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013227 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013228 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013229#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013230 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013231 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013232 return *result;
13233}
kasper.lund44510672008-07-25 07:37:58 +000013234#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013235
13236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013237RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013238 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013239 CONVERT_ARG_CHECKED(String, format, 0);
13240 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013241 String::FlatContent format_content = format->GetFlatContent();
13242 RUNTIME_ASSERT(format_content.IsAscii());
13243 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013244 LOGGER->LogRuntime(chars, elms);
13245 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013246}
13247
13248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013249RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013250 UNREACHABLE(); // implemented as macro in the parser
13251 return NULL;
13252}
13253
13254
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013255#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13256 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013257 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013258 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13259 }
13260
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013261ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013262ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13263ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13264ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13265ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13266ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13267ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13268ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13269ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13270ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13271ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13272ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13273ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13274ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13275
13276#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13277
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013278
13279RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13280 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013281 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13282 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013283 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13284}
13285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013286// ----------------------------------------------------------------------------
13287// Implementation of Runtime
13288
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013289#define F(name, number_of_args, result_size) \
13290 { Runtime::k##name, Runtime::RUNTIME, #name, \
13291 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013292
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013293
13294#define I(name, number_of_args, result_size) \
13295 { Runtime::kInline##name, Runtime::INLINE, \
13296 "_" #name, NULL, number_of_args, result_size },
13297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013298static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013299 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013300 INLINE_FUNCTION_LIST(I)
13301 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013302};
13303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013305MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13306 Object* dictionary) {
13307 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013308 ASSERT(dictionary != NULL);
13309 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13310 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013311 Object* name_symbol;
13312 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013313 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013314 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13315 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013316 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013317 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13318 String::cast(name_symbol),
13319 Smi::FromInt(i),
13320 PropertyDetails(NONE, NORMAL));
13321 if (!maybe_dictionary->ToObject(&dictionary)) {
13322 // Non-recoverable failure. Calling code must restart heap
13323 // initialization.
13324 return maybe_dictionary;
13325 }
13326 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013327 }
13328 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013329}
13330
13331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013332const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13333 Heap* heap = name->GetHeap();
13334 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013335 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013336 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013337 int function_index = Smi::cast(smi_index)->value();
13338 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013339 }
13340 return NULL;
13341}
13342
13343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013344const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013345 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13346}
13347
13348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013349void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013350 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013351 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013352 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013353 if (isolate->heap()->new_space()->AddFreshPage()) {
13354 return;
13355 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013356
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013357 // Try to do a garbage collection; ignore it if it fails. The C
13358 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013359 isolate->heap()->CollectGarbage(failure->allocation_space(),
13360 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013361 } else {
13362 // Handle last resort GC and make sure to allow future allocations
13363 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013364 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013365 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13366 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013367 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013368}
13369
13370
13371} } // namespace v8::internal